The call()
, apply()
, and bind()
methods work as expected with traditional functions, because we establish the scope for each of the methods:
const obj = {
num: 100,
};
globalThis.num = 42;
const add = function (a, b, c) {
return this.num + a + b + c;
};
console.log(add.call(obj, 1, 2, 3));
console.log(add.apply(obj, [1, 2, 3]));
const boundAdd = add.bind(obj);
console.log(boundAdd(1, 2, 3));
With arrow functions, since our add
function is essentially created on the globalThis
(global) scope, it will assume this
is the globalThis
.
const obj = {
num: 100,
};
globalThis.num = 42;
const add = (a, b, c) => this.num + a + b + c;
console.log(add.call(obj, 1, 2, 3));
console.log(add.apply(obj, [1, 2, 3]));
const boundAdd = add.bind(obj);
console.log(boundAdd(1, 2, 3));
Perhaps the greatest benefit of using arrow functions is with methods like setTimeout()
and EventTarget.prototype.addEventListener()
that usually require some kind of closure, call()
, apply()
, or bind()
to ensure that the function is executed in the proper scope.
With traditional function expressions, code like this does not work as expected:
const obj = {
count: 10,
doSomethingLater() {
setTimeout(function () {
this.count++;
console.log(this.count);
}, 300);
},
};
obj.doSomethingLater();
With arrow functions, the this
scope is more easily preserved:
const obj = {
count: 10,
doSomethingLater() {
setTimeout(() => {
this.count++;
console.log(this.count);
}, 300);
},
};
obj.doSomethingLater();