26장 ES6 함수의 추가 기능


함수의 구분

es6 이전에는 함수의 구분이없었는데, 이제 구분해서 사용한다.

Untitled 26.png|Untitled 26.png

메서드

es6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미한다.
es6 메서드는 인스턴스 생성할 수 없는 non-constructor 이다.

표준 빌드인 객체가 제공하는 프로토타입 메서드와 정적 메서드는 모두 non-constructor 임.
25장 클래스에서 봤던 것처럼 내부 슬롯을 가지고 super을 참조할 수 있다.

화살표 함수

화살표 함수와 일반함수 차이

  1. 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor
  2. 중복된 매개변수 이름을 선언할 수 없다.
  3. 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.
    스코프 체인을 통해 상위 스코프의 값들을 참조한다.

this

22장 this 참고

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }

  add(arr) {
    // add 메서드는 인수로 전달된 배열 arr을 순회하며 배열의 모든 요소에 prefix를 추가한다.
    // ①
    return arr.map(function (item) {
      return this.prefix + item; // ②
      // -> TypeError: Cannot read property 'prefix' of undefined
    });
  }
}

const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));

map에 전달된 callback 함수는 일반함수로 호출된다. 일반 함수의 호출 시 this는 전역 객체를 가르키지만, class 안에서는 strict mode가 적용되어서 this에 undefined가 바인딩되어 에러가 발생하는 모습.

콜백 함수 내부의 this문제를 해결하기 위한 방법들

  1. that 사용
  2. 고차함수에 this전달
  3. bind 메서드 이용해서 this 바인딩
add(arr) {
  // this를 일단 회피시킨다.
  const that = this;
  return arr.map(function (item) {
	// this 대신 that을 참조한다.
	return that.prefix + ' ' + item;
  });
}
add(arr) {
  return arr.map(function (item) {
	return this.prefix + ' ' + item;
  }, this); // this에 바인딩된 값이 콜백 함수 내부의 this에 바인딩된다.
}
add(arr) {
  return arr.map(function (item) {
	return this.prefix + ' ' + item;
  }.bind(this)); // this에 바인딩된 값이 콜백 함수 내부의 this에 바인딩된다.
}

화살표 함수를 사용한 this 문제 해결

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }

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

const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
// ['-webkit-transition', '-webkit-user-select']

화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조한다.
이를 lexical this 라고 한다.

화살표 함수 자체는 this바인딩을 갖기 때문에 bind 메서드를 사용해서 화살표 내부의 this를 교체할 수 없다.

메서드를 화살표 함수로 정의할 때 주의해야한다. this가 메서드를 호출한 객체를 가르키지 않기 떄문에. 프로토타입 객체에서도 프로퍼티에 화살표 함수 할당하면 동일한 문제 생길 수 잇음

// Bad
function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = () => console.log(`Hi ${this.name}`);

const person = new Person('Lee');
// 이 예제를 브라우저에서 실행하면 this.name은 빈 문자열을 갖는 window.name과 같다.
person.sayHi(); // Hi

클래스 필드에 화살표 함수 할당할 수도 있다.
그럴 경우 프로토타입 메서드가 아니라, 인스턴스의 메서드가 된다. (클래스필드에서 선언하니까)

// Bad
class Person {
  // 클래스 필드 정의 제안
  name = 'Lee';
  sayHi = () => console.log(`Hi ${this.name}`);
}

const person = new Person();
person.sayHi(); // Hi Lee

super

화살표 함수에서 super을 참조하면 상위 스코프의 super을 참조한다.

class Base {
  constructor(name) {
    this.name = name;
  }

  sayHi() {
    return `Hi! ${this.name}`;
  }
}

class Derived extends Base {
  // 화살표 함수의 super는 상위 스코프인 constructor의 super를 가리킨다.
  sayHi = () => `${super.sayHi()} how are you doing?`;
}

const derived = new Derived('Lee');
console.log(derived.sayHi()); // Hi! Lee how are you doing?

Rest 파라미터

매개변수 이름 앞에 … 붙여서 정의한 매개변수를 의미함
Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달 받는다

function foo(...rest) {
  // 매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터다.
  console.log(rest); // [ 1, 2, 3, 4, 5 ]
}

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

매개변수 기본값

매개변수 기본값 설정할 수 있음.

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

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

reference