"use strict"; // case 1 functionCar(brand) { this.brand = brand; console.log(this); } const myCar = newCar('toyota'); // this points to object: car { brand: 'toyota' }
// case 2 functionsum(a, b) { console.log(this); return a + b; } sum(1, 2); // this points to undefined
functionCar(brand) { this.brand = brand; functionstart() { console.log(this); } start(); } const myCar = newCar('toyota'); // this points to undefined because start() is a free function
// case 3 functionCar(brand) { this.brand = brand; this.start = function() { console.log(this); } } const myCar = newCar('toyota'); myCar.start(); // this points to object: Car { brand: 'toyota', start: [Function] }
// case 4 functionCar(brand) { this.brand = brand; this.start = function() { console.log(this); } } const myToyotaCar = newCar('toyota'); const myFordCar = newCar('ford'); myFordCar.start = myFordCar.start.bind(myToyotaCar); myFordCar.start(); // this points to object: Car { brand: 'toyota', start: [Function] } myToyotaCar.start.call(myFordCar); // this points to object: Car { brand: 'ford', start: [Function: bound ] }
Now you understand how this works in non-arrow functions, let’s look at what’s different in arrow functions. I mentioned this early that the second reason arrow function is introduced is to get rid of binding and having more logical this object. Instead of binding, this is derived from enclosing context. Let’s modify above examples to use arrow functions and see what’s different.
// case 2 constsum = (a, b) => { console.log(this); return a + b; } sum(1, 2); // this points to undefined, the same as non-arrow function because it's global free function
functionCar(brand) { this.brand = brand; letstart = () => { console.log(this); } start(); } const myCar = newCar('toyota'); // this points to object: Car { brand: 'toyota' }. This is different than non-arrow function, and often what we want
// case 3 functionCar(brand) { this.brand = brand; this.start = () => { console.log(this); } } const myCar = newCar('toyota'); myCar.start(); // this points to object: Car { brand: 'toyota', start: [Function] }, the same as non-arrow function which is a method of a class.
// case 4 functionCar(brand) { this.brand = brand; this.start = () => { console.log(this); } } const myToyotaCar = newCar('toyota'); const myFordCar = newCar('ford'); myFordCar.start = myFordCar.start.bind(myToyotaCar); myFordCar.start(); // this points to object: Car { brand: 'ford', start: [Function] } myToyotaCar.start.call(myFordCar); // this points to object: Car { brand: 'toyota', start: [Function] } // as you can see, bind doesn't have any effect on arrow functions.
As summary, using arrow function give more logical this, most of the time it is what you want. But it loses the ability to override this by calling bind, call or apply.