"this" and Arrow Functions
With regular functions, the value of this
is set based on how the function is called. With arrow functions, the value of this
is based on the function's surrounding context. In other words, the value of this
inside an arrow function is the same as the value of this
outside the function.
Let's check out an example with this
in regular functions and then look at how arrow functions will work.
// constructor
function IceCream() {
this.scoops = 0;
}
// adds scoop to ice cream
IceCream.prototype.addScoop = function() {
setTimeout(function() {
this.scoops++;
console.log('scoop added!');
}, 500);
};
const dessert = new IceCream();
dessert.addScoop();
Prints:
scoop added!
After running the code above, you'd_think_thatdessert.scoops
would be1
after half a millisecond. But, unfortunately, it's not:
console.log(dessert.scoops);
Prints:
0
Can you tell why?
The function passed tosetTimeout()
is called withoutnew
, withoutcall()
, withoutapply()
, and without a context object. That means the value ofthis
inside the function is the global object and NOTthedessert
object. So what actually happened was that a newscoops
variable was created (with a default value ofundefined
) and was then incremented (undefined + 1
results inNaN
):
setTimeout()에 전달된 함수는 call()이 없으면 apply()가없고 context 객체가 없으면 new없이 호출됩니다. 즉, 이 함수 내부 값은 디저트 객체가 아니라 전역 객체입니다. 그래서 실제적으로 새로운 scoops 변수가 만들어졌고 (기본값은 undefined 임) 다음 증분되었습니다 (NaN에서 undefined + 1 결과).
console.log(scoops);
Prints:
NaN
One way around this is to use closure:
// constructor
function IceCream() {
this.scoops = 0;
}
// adds scoop to ice cream
IceCream.prototype.addScoop = function() {
const cone = this; // sets `this` to the `cone` variable
setTimeout(function() {
cone.scoops++; // references the `cone` variable
console.log('scoop added!');
}, 0.5);
};
const dessert = new IceCream();
dessert.addScoop();
The code above_will_work because instead of usingthis
inside the function, it sets thecone
variable tothis
and then looks up thecone
variable when the function is called. This works because it's using the value of thethis
outside the function. So if we check the number of scoops in our dessert right now, we'll see the correct value of1
:
위의 코드는 함수 내부에서 this를 사용하는 대신 cone 변수를 this로 설정하고 함수가 호출 될 때 cone 변수를 조회하기 때문에 작동합니다. 이것은 함수 외부의 this의 값을 사용하기 때문에 작동합니다. 따라서 디저트의 스푼 수를 지금 확인하면 올바른 값인 1이 표시됩니다.
console.log(dessert.scoops);
Prints:
1
Well that's exactly what arrow functions do, so let's replace the function passed tosetTimeout()
with an arrow function:
// constructor
function IceCream() {
this.scoops = 0;
}
// adds scoop to ice cream
IceCream.prototype.addScoop = function() {
setTimeout(() => { // an arrow function is passed to setTimeout
this.scoops++;
console.log('scoop added!');
}, 0.5);
};
const dessert = new IceCream();
dessert.addScoop();
Since arrow functions inherit theirthis
value from the surrounding context, this code works!
console.log(dessert.scoops);
Prints:
1
WhenaddScoop()
is called, the value ofthis
insideaddScoop()
refers todessert
. Since an arrow function is passed tosetTimeout()
, it's using its surrounding context to determine whatthis
refers to inside itself. So sincethis
_outside_of the arrow function refers todessert
, the value ofthis
_inside_the arrow function will also refer todessert
.
addScoop()이 호출되면 addScoop() 내부의 값은 디저트를 참조합니다. Arrow function은 setTimeout()에 전달되기 때문에 주위의 컨텍스트를 사용하여 이 함수가 내부적으로 무엇을 참조하는지 결정합니다. 따라서 arrow function 바깥 쪽은 디저트를 참조하기 때문에 화살표 함수 내부의 값도 디저트를 나타냅니다.
Now what do you think would happen if we changed theaddScoop()
method to an arrow function?
// constructor
function IceCream() {
this.scoops = 0;
}
// adds scoop to ice cream
IceCream.prototype.addScoop = () => { // addScoop is now an arrow function
setTimeout(() => {
this.scoops++;
console.log('scoop added!');
}, 0.5);
};
const dessert = new IceCream();
dessert.addScoop();
Yeah, this doesn't work for the same reason - arrow functions inherit theirthis
value from their surrounding context. Outside of theaddScoop()
method, the value ofthis
is the global object. So ifaddScoop()
is an arrow function, the value ofthis
insideaddScoop()
is the global object. Which then makes the value ofthis
in the function passed tosetTimeout()
_also_set to the global object!