var self = this; // Dammi una lametta...
The most common use are:
When you call a function the value of this depends on the mode: normal or strict
function log() {
console.log(this);
}
log(); // window
In strict mode the value of this is undefined
'use strict';
function log() {
console.log(this);
}
log(); // undefined
We can arbitrarily change the value of this with two function:
let robot = {
name: 'Robocop'
};
function kill(toKill) {
console.log(this.name + ' will kill ' + toKill);
}
kill.call(robot, 'you') // Robocop will kill you
kill.apply(robot, ['you']) // Robocop will kill you
A constructor is a function invoked with the new operator that return the instance of an object.
When a constructor is invoked with new, this is bound to the newly created object.
function Dog(name) {
this.name = name;
}
let pluto = new Dog('Pluto');
pluto.name; // 'Pluto'
this refers to the receiver, the object on which the method has been called.
let obj = {
prop: 'a prop',
method() {
console.log(this.prop);
}
};
obj.method(); // 'a prop'
In browsers, the top-level scope is the global scope and this refers to the global object (window)
When you call a constructor without the new operator you are invoking
it like a real function!
function Point(x, y) {
this.x = x;
this.y = y;
}
let point = Point(10, 20);
// Constructor doesn't return the object instance!
console.log(point); // undefined
// Global variables created! Gomblotto!1!1
window.x; // 10
window.y; // 20
'use strict';
function Point(x, y) {
this.x = x;
this.y = y;
}
// TypeError: Cannot set property 'x' of undefined
let point = Point(10, 20);
Sometimes we forgot about Javascript lexical scope!
let component = {
width: 800,
init() {
document.addEventListener('click', function(e) {
console.log(this.width);
});
}
};
// On document's click this.width is undefined
component.init();
We can store the value of this
let component = {
width: 800,
init() {
// Woooooo
let self = this;
document.addEventListener('click', function(e) {
console.log(self.width);
});
}
};
component.init();
We can use a sexy arrow function*
let component = {
width: 800,
init() {
document.addEventListener('click', e => {
console.log(this.width);
});
}
};
component.init();
*only for ES6 brave guys!
Or use Function.prototype.bind
let component = {
width: 800,
init() {
document.addEventListener('click', function(e) {
console.log(this.width);
}.bind(this));
}
};
component.init();
If we retrieve the value of a method, instead of invoking it, we turn that method into a function
pointing this to the global object!
let counter = {
count: 0,
increment() {
this.count++;
console.log(this.count);
}
};
setInterval(counter.increment, 1000);
Use Function.prototype.bind to create a new function with this bound to the right object.
let counter = {
count: 0,
increment() {
this.count++;
console.log(this.count);
}
};
setInterval(counter.increment.bind(counter), 1000);
When eval is called directly this point to surrounding eval context
let x = 'global';
function directly() {
let x = 'local';
console.log(eval('x')); // local
}
directly();
// Point depending on the context;
function nonStrict() {
console.log(eval('this')); // window
}
nonStrict();
function strict() {
'use strict';
console.log(eval('this')); // undefined
}
strict();
When eval is called indirectly this always point to the global object
let x = 'global';
function indirectly() {
let x = 'locals';
console.log(window.eval('x'));
}
indirectly();
// Let's try with this
let obj = {
indirectly: function() {
console.log(window.eval('this'));
}
};
obj.indirectly();