ECMAScript 2015부터 화살표 함수의 문법이 도입되었다. 하지만 화살표 함수와 일반 함수는 여러 가지 차이가 있다. 뭐가 다를까?
// (param1, param2, paramN) => expression
// ES5 Regular function
var add = function(x, y) {
return x + y;
};
// ES6 Arrow function
let add = (x, y) => { return x + y };
화살표 함수는 코드를 더 간결하게 표현할 수 있게 해 준다.
자바스크립트에서는 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정(dynamic context)된다. 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 게 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지(the value of 'this' depends on how the function is invoked)에 따라 this에 바인딩할 객체가 동적으로 결정된다.
function foo () {
console.log("Simple function call");
console.log(this === window);
}
foo(); //prints true on console
console.log(this === window) //Prints true on console.
즉 여기서는 함수가 global context에서 호출(실행)되었기 때문에 this === window 인 것이다.
앞에서 살펴보았듯이, 일반 함수는 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.
화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 동적으로 결정되는 일반 함수와 달리, 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다(this value inside of an arrow function always equals this value from the outer function). 이를 Lexical(선언된 곳) this라 한다.
화살표 함수의 this 바인딩 객체 결정 방식은 함수의 상위 스코프를 결정하는 방식인 lexical scope와 유사하다.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
// this는 상위 스코프인 prefixArray 메소드 내의 this를 가리킨다.
return arr.map(x => `${this.prefix} ${x}`);
};
const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
window.x = 1;
const normal = function () { return this.x; };
const arrow = () => this.x;
console.log(normal.call({ x: 10 })); // 10
console.log(arrow.call({ x: 10 })); // 1
// Bad
const person = {
name: 'Lee',
sayHi: () => console.log(`Hi ${this.name}`)
};
person.sayHi(); // Hi undefined
위 예제의 경우, method로 정의한 화살표 함수 내부의 this는 method를 호출한 객체를 가리키지 않고 상위 context인 전역 객체 window를 가리킨다.즉 this는 어디에도 바인딩되지 않는다.
이 경우 method를 위한 단축 표기법인 ES6의 축약 메소드 표현을 사용하는 것이 좋다.
// Good
const person = {
name: 'Lee',
sayHi() {
console.log(`Hi ${this.name}`);
}
};
person.sayHi(); // Hi Lee
// Bad
const person = {
name: 'Lee',
};
Object.prototype.sayHi = () => console.log(`Hi ${this.name}`);
person.sayHi(); // Hi undefined
화실표 함수로 객체의 method를 정의하였을 때와 같은 문제가 발생한다.method를 호출한 객체를 가리키지 않고, 전역 객체를 가리킨다. 따라서 prototype에 메소드를 할당하는 경우, 일반 함수를 할당한다.
//Good
const person = {
name: 'Lee',
};
Object.prototype.sayHi = function(){
console.log(`Hi ${this.name}`)
};
person.sayHi(); // Hi Lee
화살표 함수는 constructor function으로 사용할 수 없다. constructor function은 prototype 프로퍼티를 가지며 prototype프로퍼티가 가리키는 프로토타입 객체의 constructor을 사용한다. 하지만 화살표 함수는 prototype 프로퍼티를 가지고 있지 않으므로 constructor로 사용될 수 없다.
const Foo = () => {};
// 화살표 함수는 prototype 프로퍼티가 없다
console.log(Foo.hasOwnProperty('prototype')); // false
const foo = new Foo(); // TypeError: Foo is not a constructor
일반 함수를 사용하면 이 함수가 하고자 하는 게 명확하지만, 화살표 함수를 사용하면 알기 어려운 경우도 많다. 그리고 화살표 함수도 과도하게 사용하면 가독성이 떨어질 수 있으니 주의하자.
** 참고