Arrow function expressions - JavaScript | MDN
function myFunc() {})const myfunc = function(){})const myFunc = () => {})this, arguments, super에 대한 바인딩이 없으며, 메소드로 사용해서는 안된다.
this 바인딩이 없다는 것은 arrow function 내부의 this는 해당arrow function이 정의되는 공간의 this context를 따라간다는 뜻이다.new를 사용해 화살표 함수를 호출하면 TypeError가 발생한다)
new.target 키워드 역시 사용할 수 없다. (사용시 Uncaught SyntaxError 발생)yield를 사용할 수 없으며, 따라서 generator function으로서 생성될 수 없다.this의 동작 원리this context를 가지지 않는다. 대신, 함수 정의 시 enclosing lexical context를 따라간다. 즉 arrow function이 만들어질 당시 해당 함수를 감싸고 있는 주위의 context를 따라간다는 것.
globalThis를 가리키고(strict mode면 undefined), 함수 메소드 안에 정의 시 해당 메소드 함수의 context를 따라간다. 즉 메소드가 어떤 객체에 의해 호출되는 경우 내부의 arrow function의 this역시 해당 객체를 가리키게 된다.this가 auto-bound 된다.
this context에 영구적으로 묶여 있다는 것이다.arrow function은 스스로의 this를 갖지 않기 때문에, 일반 객체 메소드로 사용해선 안된다고 한다. (일반 객체는 클래스와 다르게 별도의 this 컨텍스트를 갖고 있지 않고 따라서 전역객체나 undefined를 가리키게 된다.)
const obj = {
i: 10,
b: () => console.log(this.i, this),
c() {
console.log(this.i, this);
},
};
obj.b(); // logs undefined, Window { /* … */ } (or the global object)
obj.c(); // logs 10, Object { /* … */ }
이건 좀 헷갈릴 수 있는데, 메소드 자체는 일반 함수로 정의하고, 그 함수 안에서 arrow function을 사용하는 상황을 말하는 것이다.
당연한 말이지만, 객체의 메소드를 일반 함수로 정의한 경우에는, 메소드 내부의 this는 해당 객체 context를 가리킨다. 그런데 arrow function은 자신을 감싸고 있는 scope의 context의 this를 따라가므로, 일반 메소드 함수 내부에서 다시 arrow function을 사용하는 경우에는 이 arrow function의 this 역시 해당 객체를 가리키게 된다.
let user = {
firstName: "Ilya",
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // Ilya
arrow 함수 내부의 this는 자신을 감싸고 있는 sayHi함수가 가리키는 this를 가리키게 된다는 것이다.
user가 sayHi를 호출하고 있으므로 여기서는 user 객체를 가리키게 된다.enclosing scope의 context를 따라가는것 뿐이므로, 당연히 기존 객체에 바인딩 되지는 않는다. 무슨말이냐 하면, 아래처럼 된다는 말이다.
const func1 = user.sayHi;
func1(); // undefined
let user2 = {
firstName: "Kihoon",
}
user2.sayHi = user.sayHi;
user2.sayHi(); // Kihoon
arrow 함수는 자신을 감싸고 있는 sayHi 메소드의 this context를 따른다. user1에 의해 호출될 때 sayHi의 this는 user1을, user2에 의해 호출될때는 user2를 가리킨다. 따라서 arrow도 자신을 감싸고 있는 sayHi가 가리키는 this를 따라가는 것이다.반면 클래스 필드로서는 arrow function 사용이 가능한데, 클래스는 this 컨텍스트를 가지고 있기 때문이다.
따라서 클래스 필드로 정의된 arrow function 내부의 this는 제대로 인스턴스 객체를 가리키게 되는 것이다. (물론 만약 static field라면 class 자체를 가리킨다)
이때의 this는 심지어 실행 컨텍스트execution context가 바뀌어도 변하지 않는다(마치 bind() 메소드를 사용한것과 같은 현상을 보여준다). 왜냐하면 클래스의 arrow function property의 바인딩은 엄밀히 말하면 함수의 자체 바인딩이 아니라, closure이기 때문이다.
class C {
a = 1;
autoBoundMethod = () => {
console.log(this.a);
};
}
const c = new C();
c.autoBoundMethod(); // 1
const func1 = c.autoBoundMethod;
func1(); // 1
// 일반 객체의 메소드였더라면 당연히 undefined인 상황
클래스의 arrow function property는 이러한 명시적 바인딩 동작을 보여주기 때문에, “auto-bound methods”라고 불리기도 한다. 만약 일반 메소드로 위와 같은 효과를 내려면 아래와 같이 실제로 bind() 메소드를 사용해서 구현해야 한다.
class C {
a = 1;
constructor() {
this.method = **this.method.bind(this);**
}
method() {
console.log(this.a);
}
}
다만 class property로 arrow function을 사용하게 되면, (클로저를 생성하여?)각 인스턴스마다 메소드의 복사본을(copy) 가지게 되기 때문에(그래야 각 인스턴스마다 인스턴스 자신을 가리키는 this context를 가진 메소드를 가질 수 있다 ~ 고 추측한다. ), 메모리 사용을 증가시킨다는 문제점이 있다. (이는 .bind() 메소드를 이용한 auto-bound method역시 마찬가지다)
this scope when using a callback inside a method