If you want a very simplified version:
this
points to the context. In the event handlers, this
is the element that has received the event (the button, the div, the link ...). If you call a function as if it were a method, this
is the object. But that the function is declared as a method does not ensure that it is called as such.
If you want a longer and "didactic" version, with examples:
The behavior of this
is a little special in Javascript: It indicates the context in which you are executing the code. If you are in the global context (you are not inside any function), this
is window
. If you call a function simply by using the name of the function, the context is maintained:
console.log(this===window);
function test() {
console.log(this===window);
if (this!==window) {
console.log(this);
}
}
test();
But in strict mode, the context when calling a function using its name is undefined
:
'use strict';
console.log(this===window);
function test() {
console.log(this===window);
if (this!==window) {
console.log(this);
}
}
test();
But if that function is an attribute of an object, then this
becomes that object:
function test() {
console.log('Es window?:' + (this===window));
if (this!==window) {
console.log('Es obj?:' + (this===obj));
}
}
console.log('Modo no estricto');
var obj={
prueba: 'hola'
}
test();
console.log('Como método');
obj.metodo=test;
obj.metodo();
Then, when we define a callback function, we can have problems if we do not know which is the context where the function is executed:
class Contador {
constructor() {
this.count=0;
}
incrementar() {
this.count++;
}
}
let c= new Contador()
c.incrementar();
console.log(c.count)
let funcionInc=c.incrementar;
//falla porque el contexto no es un objeto Contador
funcionInc();
Imagine that we have an event that we want to deal with our counter object:
class Contador {
constructor() {
this.count=0;
}
incrementar() {
if (this.count !== undefined) {
this.count++;
} else {
console.log('No hay count para incrementar!');
}
}
}
let c= new Contador();
$('button').on('click',c.incrementar);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>
Solutions to this problem there are several:
One is to surround the execution in another function:
class Contador {
constructor() {
this.count=0;
}
incrementar() {
if (this.count !== undefined) {
this.count++;
console.log(this.count);
} else {
console.log('No hay count para incrementar!');
}
}
}
let c= new Contador();
$('button').on('click',function () {c.incrementar();});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>
And another solution is to use bind()
:
class Contador {
constructor() {
this.count=0;
}
incrementar() {
if (this.count !== undefined) {
this.count++;
console.log(this.count);
} else {
console.log('No hay count para incrementar!');
}
}
}
let c= new Contador();
//con bind fijamos el contexto
let funcion=c.incrementar.bind(c);
$('button').on('click',funcion);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>
The arrow functions are a bit special, because they assign the context at the moment they are defined, not when they are executed:
class Contador {
constructor() {
this.count=0;
this.incrementar= () => {
this.count++;
console.log(this.count);
}
}
}
let c= new Contador();
//no hace falta bind, el contexto se fijó al declarar la función
$('button').on('click',c.incrementar);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Click</button>