JS — “this” keyword

“this” is not assigned a value until an object invokes the function where this is defined

this” in javascript is bound to runtime (the context), i.e. who is actually calling the method. One easy tip for knowing the context is that: it’s the one before the dot of () 😁

The best way to learn about `this` is from examples.

The normal “this”

var person = {
firstName: 'Michael',
lastName: 'Jackson',
fullName: function() {
console.log(this.firstName + ' ' + this.lastName);
console.log(person.firstName + ' ' + person.lastName); // same
}
}

You can use `this` inside an object to refer to that object itself. This is a easy one.

this” in global scope

When used in global scope, `this` refers to `window` object.

var name = 'winXp';
function showName() {
console.log(this.name); // showName() is defined in global scope so "this" refers to the 'window' object
}
var local = { 
name: 'osx',
function showName() {
console.log(this.name); // showName() is defined in local var scope so "this" refers to the local object
}
}
showName();  // winXp
window.showName(); // winXp
local.showName(); // osx

There’re four scenarios where ‘this’ is misleading.

1. when a method passed as a callback

var user = { 
data: [1, 2, 3],

onClick: function() {
console.log(this.data[0]);
}
}
$("button").click(user.onClick) // Cannot read property '0' of undefined

Because $(“button”) will pass the button object into the click handler, so “this” becomes the button object.

Solution to fix “this” when a method is passed as a callback

=> Use bind(), apply() or call() to specifically set the value of this.

$("button").click(user.onClick.bind(user));

2. “this” inside closure

Rule of thumb: Closures cannot access outer functions’ “this” variable. “this” becomes ‘window’.

var user = { 
data: [1, 2, 3],
name: 'naruto',
onClick: function() {
this.data.forEach(function(d) {
console.log(this.name); // undefined. this=[object Window]. Inner function cannot access outer function's "this".
});
}
}
user.onClick();  

“this” will lose context in the inner function. When losing context it will become ‘window’.

Solution to maintain `this` inside anonymous functions:

1). that = this (utilizing closure to remember `this`)

var user = { 
data: [1, 2, 3],
name: 'naruto',
onClick: function() {
var that = this;
this.data.forEach(function(d) {
console.log(that.name); // 'naruto'
});
}
}
user.onClick();

2) Arrow function (ES6)

ES6 arrow function will preserve the `this` inside the anonymous function.

var user = { 
data: [1, 2, 3],
name: 'naruto',
onClick: function() {
this.data.forEach(() => {
console.log(this.name); // 'naruto'
});
}
}
user.onClick();

3. When a method is assigned to a variable

var data = ["global"];
var user = {
data:["user"],
showData: function() {
console.log(this.data[0]);
}
}
// assign to a variable
var showUserData = user.showData;
showUserData(); // "global"

This is same as:

var data = ["global"];
var user = { ... };
var showUserData = function() { 
console.log(this.data[0])
};
showUserData(); // called from global context.

Solution for maintaining this when method is assigned to a variable:

=> use bind() .

var showUserData = user.showData.bind(user);
showUserData(); // "user"

4. When borrowing methods

// we want to borrow sum() from hasSum for noSum
var noSum = {
data: [1, 3],
total: 0 // initial value
};
var hasSum = {
data: [3, 5],
total: 0,
sum: function() {
console.log(this.data[0] + this.data[1])
}
}
noSum.total = hasSum.sum(); // 8 instead of 4

Because we are calling from hasSum object.

Solution for fixing this when borrowing methods:

=> use apply() or call()

noSum.total = hasSum.sum.apply(noSum);
OR
noSum.total = hasSum.sum.call(noSum);

Reference

Show your support

Clapping shows how much you appreciated VLT’s story.