목차
화살표 함수(Arrow Functions)
화살표 함수는 function 표현식을 짧게 쓰는 방법이지만 동일한 함수는 아니다. 매개변수와 반환식이 간단한 콜백에 적합하고, this를 바깥 문맥에서 그대로 사용한다. 이 차이를 모르고 객체 메서드나 생성자로 쓰면 예상과 다른 동작이 나온다.
본문과 반환값
const square = x => x * x; // 표현식의 결과를 반환
const add = (x, y) => { return x + y; }; // 블록에서는 return 필요
const makePair = x => ({ value: x }); // 객체 리터럴은 괄호로 감싼다
console.log([1, 2, 3].map(square)); // [1, 4, 9]
console.log(makePair(2)); // { value: 2 }
중괄호로 시작하면 자바스크립트는 이를 함수 본문 블록으로 해석한다. 객체 리터럴을 바로 반환할 때 ({ ... })로 감싸는 이유다. 블록 본문에서 return을 빠뜨리면 undefined가 반환된다. x => x * x는 함수를 생성하는 식이며 const square = ... 같은 변수에 담거나 다른 함수에 인자로 넘겨 쓴다.
this는 호출 방식으로 바뀌지 않는다
일반 함수는 메서드로 호출할 때 호출 객체가 this가 된다. 화살표 함수는 자신의 this를 만들지 않고 정의된 위치의 바깥 this를 사용한다.
const prefixer = {
prefix: "Hello",
attach(names) {
return names.map(name => `${this.prefix} ${name}`);
},
};
console.log(prefixer.attach(["Kim", "Lee"]));
// ['Hello Kim', 'Hello Lee']
attach는 일반 메서드여서 this === prefixer다. 그 안의 화살표 콜백은 같은 this를 캡처한다. 콜백을 function(name) { ... }으로 바꾸면 그 함수의 this는 별도로 결정되므로 같은 코드가 동작하지 않을 수 있다. call, apply, bind로 화살표 함수의 this를 다시 묶을 수도 없다.
반대로 객체 메서드를 화살표로 정의하는 것은 대부분 의도와 맞지 않는다.
const person = {
name: "Paik",
sayHello() { return `Hello ${this.name}`; },
};
console.log(person.sayHello()); // Hello Paik
person.sayHello = () => ...는 바깥 this를 사용하므로 person.name을 가리키지 않는다. 브라우저 전역이 반드시 window일 것이라고 가정하는 것도 부정확하다. 모듈과 엄격 모드에서는 바깥 this가 다를 수 있다.
생성자와 이벤트 리스너
화살표 함수에는 생성자로 필요한 자체 prototype이 없어서 new (() => {})는 TypeError가 난다. 생성이 필요하면 class나 일반 함수를 사용한다. DOM 이벤트 리스너에서 리스너가 붙은 요소를 this로 받으려면 일반 함수를 쓰거나, 화살표 함수에서는 event.currentTarget을 명시적으로 읽는다.
button.addEventListener("click", function (event) {
console.log(this === event.currentTarget); // true
});
button.addEventListener("click", event => {
console.log(event.currentTarget); // 리스너가 붙은 요소
});
위 button은 DOM 요소가 이미 있다는 전제의 예제다. 화살표가 무조건 금지되는 상황은 아니다. 필요한 this가 어디서 오는지에 따라 선택한다. 여러 줄의 상태 변경을 수행하는 콜백보다 순수한 변환 함수를 작성하면 실행 결과를 예측하기 쉽다.
참고: MDN 화살표 함수