26장 ES6 함수의 추가 기능- 모던 자바스크립트 Deep Dive

Minju Kim·2022년 8월 10일
0

Deep Dive

목록 보기
18/23
post-thumbnail

📕 26.1 함수의 구분

1. ES6 이전의 함수

ES6 이전의 함수는 사용목적에 따라 명확히 구분되지 않아, 모두 일반함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수도 있어 혼란스러우며 실수를 유발할 가능성이 높았다.

다시 말해, 모든 함수가 callable이면서 constructor다는 것이다.

ES6 이전의 메서드

객체에 바인딩 된 메서드 역시도 일반함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수 도 있었다는 것이다. 게다가 객체에 바인딩 된 함수가 constructor라는 것은 이 메서드가 prototype을 가지며, 프로토타입 객체도 생성한다는 것을 의미하기 때문에 문법상, 기능상 문제가 발생한다.

ES6 이전의 콜백함수

콜백함수 역시 보조함수인데도 불구하고 constructor이며 프로토타입을 생성했는데 아주 혼란을 많이 야기했다.

👍 2. ES6 변경사항

일반함수는 constructor이지만 ES6의 메서드와 화살표 함수는 non-constructor이다.

📕 26.2 메서드

이전에는 객체에 바인딩된 함수를 일컫는 의미로 사용되었으나, ES6의 메서드는 메서드 축약 표현으로 정의된 함수만을 일컫는다.

const obj = {
  x: 1,
  
  // 메서드
  foo() {return this.x}
  
  // 일반함수
  bar : function(){return this.x;}

ES6에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor다. 따라서 ES6 메서드는 생성자 함수로서 호출할 수 없다.

new obj.foo(); // TypeError:obj.foo is not a contructor
new obj.bar(); // bar{}

인스턴스를 생성할 수 없다는 것은 prototype 프로퍼티가 없고 프로토타입도 생성하지 않는다는 의미이다.

ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 갖는다. super 참조는 내부 슬롯 [[HomeObject]]를 사용하여 수퍼클래스의 메서드를 참조하므로 ES6 메서드는 super 키워드를 사용할 수 있다.

📕 26.3 화살표 함수

💖 26.3.1 화살표 함수 정의

[함수 정의 & 매개변수 선언]
1. 함수 표현식으로만 정의할 수 있다. const multiply = (x,y) => x+y;
2. 매개변수 여러개인 경우 소괄호 안에 매개변수를 선언 const arrow = (x, y) => {...}
3. 매개변수가 하나인 경우 소괄호 생략가능 const arrow = x => {...}
4. 매개변수가 없는 경우 소괄호 생략할 수 없다.const arrow = () => {...}

[함수 몸체 정의]
1. 표현식이 아닌 문인 경우 중괄호 {}를 생략할 수 없다.

	 ⛔️ const arrow = () => const x= 1const arrow = () => { return const x = 1;}
	
  1. 객체 리터럴을 반환하는 경우 소괄호()로 감싸줘야 한다.

    const create = (id, content) => ({id, content});
    // 다음과 같다.
    const create = (id, content) => { return {id, content}; };
  2. 함수 몸체가 여러 개의 문으로 구성된다면 중괄호를 생략할 수 없다.

  3. 화살표 함수도 즉시 실행함수로 사용할 수 있다.

const person = (name => ({ sayHi() { return `Hi? My name is ${name}.`}}))('Lee');
console.log(person.sayHi())
  1. 화살표 함수도 일급 객체이므로 고차함수에 인수로 전달할 수 있다.
[1,2,3].map(function(v) {
  return v * 2;
});

[1,2,3].map(v => v * 2); 

💖 26.3.2 화살표 함수와 일반 함수의 차이

  1. 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor다. new 붙여서 생성자 함수로 호출할 수 없다.
  2. 중복된 매개변수 이름을 선언할 수 없다.
    일반함수는 가능하다. function normal(a,a) {return a + a;}
  3. 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.
    따라서 화살표 함수 내부에서 이를 참조하면 스코프 체인을 통해 상위 스코프의 this, arguments, super, new.target을 참조한다.

💖 26.3.3 this

화살표 함수의 this와 일반 함수의 this는 다르게 동작한다.
this는 함수가 호출되는 시점에 어떻게 호출되었는지에 따라 동적으로 결정된다.

일반 함수로서 호출되는 모든 함수 내부의 this는 전역 객체를 가리킨다. 그런데 클래스 내부의 모든 코드에는 strict mode가 암묵적으로 적용된다. strict mode에서 일반함수로서 호출된 모든 함수의 내부의 this에는 전역 객체가 아닌 undefined가 바인딩되므로 일반 함수로서 호출되는 Array.prototype.map 메서드의 콜백 함수 내부의 this에는 undefined가 바인딩된다.

이 때, "콜백 함수 내부의 this 문제"가 발생한다. 즉, 콜백 함수의 this와 외부 함수의 this가 서로 다른 값을 가리키고 있을 수 있게 된다. 이를 해결하기 위해 ES6 이전에는 다음과 같은 방법을 사용했다.
1. this를 일단 that에 저장해 회피시킨다.
2. Array.prototype.map의 두 번재 인수로 add 메서드를 호출한 prefixer 객체를 가리키는 this를 전달한다.
3. bind메서드를 사용해 add메서드를 호출한 prefixer객체를 가리키는 this를 바인딩한다.

🥹 화살표 함수는 이 "콜백 함수 내부의 this 문제"를 해결할 수 있다.

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }
  
  add(arr) {
    return arr.map(item => this.prefix + item);
  }
}

화살표 함수는 함수 자체의 this바인딩을 갖지 않는다. 따라서 화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조하는데, 이를 lexical this라고 한다. 마치 렉시컬 스코프와 같이 화살표 함수의 this가 함수의 정의된 위치에 의해 결정된다는 것을 의미한다.

만약 화살표 함수 두 개가 중첩되어있다면, 상위 화살표 함수에도 this바인딩이 없으므로 스코프 체인상에서 가장 가까운 상위 함수 중에서 화살표 함수가 아닌 함수의 this를 참조한다.

만약 화살표 함수가 전역 함수라면 화살표 함수의 this는 전역 객체를 가리킨다.

const foo = () => console.log(this);
foo(); // window

프로퍼티에 할당한 화살표 함수도 스코프 체인 상에서 가장 가까운 상위 함수 중에서 화살표 함수가 아닌 함수의 this를 참조한다.

화살표 함수는 함수 자체의 this 바인딩을 갖지 않기 때문에 call, bind, apply메서드를 사용해도 화살표 함수 내부의 this를 교체할 수 없다. 언제나 상위 스코프의 this 바인딩을 참조한다.

✨ 따라서 메서드를 화살표 함수로 정의하는 것은 피해야 한다. ES6메서드가 아니라 일반적인 의미의 메서드일 때! 메서드를 정의할 때는 ES6 메서드 축약 표현으로 정의하는게 바람직하다.

//Good
const person = {
  name = 'Lee',
  sayHi() {
    console.log(`Hi, ${this.name}`)
  }
}

person.sayHi();

또한, 클래스 필드에 할당한 화살표 함수는 프로토타입 메서드가 아니라 인스턴스 메서드가 되기에,메서드를 정의할 때는 무조건 축약 표현으로 사용하는 것이 좋다.

💖 26.3.4 super

화살표 함수는 함수 자체의 super 바인딩을 갖지 않기 때문에, 화살표 함수 내부에서 super를 참조하면 this와 마찬가지로 상위 스코프의 super를 참조한다.

💖 26.3.5 arguments

화살표 함수는 함수 자체의 arguments바인딩을 갖지 않기 때문에, 화살표 함수 내부에서 argumets를 참조하면 this와 마찬가지로 상위 스코프의 argumets를 참조한다.

(function() {
  const foo = () => console.log(arguments);
  foo(3,4);
}(1,2)));

// arguments는 3,4가 아닌, 상위 스코프의 arguments인 1,2를 가리키게 된다.

따라서! 화살표 함수로 가변 인자 함수를 구현해야 할 때는 반드시 Rest 파라미터를 사용해야 한다.

📕 26.4 Rest 파라미터

✍️ Rest 파라미터는 함수에 전달된 인수들을 목록을 배열로 전달받는다.

function foo(...rest){
  console.log(rest); // [1,2,3,4,5]
}

foo(1,2,3,4,5)

Rest parameter의 위치는 가장 마지막이어야한다.

function foo(param1, param2, ...rest)
function foo(...rest, parma1, parma2) ⛔️

Rest parameter는 단 하나만 선언할 수 있다.

function foo(...rest1, ...rest2){ } ⛔️

Rest parameter는 함수 정의 시 선언한 매개변수를 나타내는 함수 객체의 length 프로퍼티에 영향을 주지 않는다.

function bar(x, ...rest) {}
console.log(bar.length); // 1

✍️ arguments대신 Rest Parameter를 사용하면 배열로 변환하지 않아도 배열을 반환받을 수 있다.

✍️ 화살표 함수는 arguments를 가질 수 없기 때문에 반드시 Rest 파라미터를 사용해야 한다.

📕 26.5 매개변수 기본값

자바스크립트 엔진이 매개변수의 개수와 인수의 개수를 체크하지 않기 때문에, 매개변수 기본값을 사용하면 초기화와 인수체크를 간소화할 수 있다.
매개변수 기본값은 매개변수에 인수를 전달하지 않은 경우와 undefiined를 전달한 경우에만 유효하다.

function logName(name = 'Lee'){
  console.log(name);
}

logName(); //Lee
logName(undefined); //Lee
logName(null); // null

profile
⚓ A smooth sea never made a skillful mariner

0개의 댓글