176 lines
6.1 KiB
Markdown
176 lines
6.1 KiB
Markdown
|
---
|
|||
|
title: this reference
|
|||
|
localeTitle: esta referencia
|
|||
|
---
|
|||
|
## `this` referencia
|
|||
|
|
|||
|
En JavaScript, cada función tiene `this` referencia creada automáticamente cuando la declara. Esta referencia es bastante similar a `this` referencia en otros lenguajes basados en clases como Java o C # (JavaScript es un lenguaje basado en prototipos y no tiene un concepto de "clase"): _apunta al objeto que está llamando a la función_ (este objeto a veces llamado como _contexto_ ). Sin embargo, en JavaScript, _`this` referencia dentro de las funciones puede vincularse a diferentes objetos dependiendo de dónde se llame la función_ . Aquí hay 5 reglas básicas para `this` enlace en JavaScript:
|
|||
|
|
|||
|
### Regla 1
|
|||
|
|
|||
|
Cuando se llama a una función en el ámbito global, `this` referencia está vinculada por defecto al **objeto global** ( `window` en el navegador o `global` en Node.js). Por ejemplo:
|
|||
|
|
|||
|
```javascript
|
|||
|
function foo() {
|
|||
|
this.a = 2;
|
|||
|
}
|
|||
|
|
|||
|
foo();
|
|||
|
console.log(a); // 2
|
|||
|
```
|
|||
|
|
|||
|
Nota: Si se declara la `foo()` función anterior en modo estricto, a continuación, se llama a esta función en el ámbito global, `this` será `undefined` y asignación `this.a = 2` tirará `Uncaught TypeError` excepción.
|
|||
|
|
|||
|
### Regla 2
|
|||
|
|
|||
|
Examinemos el siguiente ejemplo:
|
|||
|
|
|||
|
```javascript
|
|||
|
function foo() {
|
|||
|
this.a = 2;
|
|||
|
}
|
|||
|
|
|||
|
var obj = {
|
|||
|
foo: foo
|
|||
|
};
|
|||
|
|
|||
|
obj.foo();
|
|||
|
console.log(obj.a); // 2
|
|||
|
```
|
|||
|
|
|||
|
Claramente, en el fragmento de código anterior, la función `foo()` se llama con _context_ es el objeto `obj` y `this` referencia ahora está vinculada a `obj` . Entonces, cuando se llama a una función con un objeto de contexto, `this` referencia se vinculará a este objeto.
|
|||
|
|
|||
|
### Regla 3
|
|||
|
|
|||
|
`.call` , `.apply` y `.bind` pueden usarse en el sitio de la llamada para enlazar explícitamente `this` . Usar `.bind(this)` es algo que puede ver en muchos componentes de React.
|
|||
|
|
|||
|
```javascript
|
|||
|
var foo = function() {
|
|||
|
console.log(this.bar)
|
|||
|
}
|
|||
|
|
|||
|
foo.call({ bar: 1 }) // 1
|
|||
|
```
|
|||
|
|
|||
|
Aquí hay un ejemplo rápido de cómo se usa cada uno para unir `this` :
|
|||
|
|
|||
|
* `.call()` : `fn.call(thisObj, fnParam1, fnParam2)`
|
|||
|
* `.apply()` : `fn.apply(thisObj, [fnParam1, fnParam2])`
|
|||
|
* `.bind()` : `const newFn = fn.bind(thisObj, fnParam1, fnParam2)`
|
|||
|
|
|||
|
### Regla 4
|
|||
|
|
|||
|
```javascript
|
|||
|
function Point2D(x, y) {
|
|||
|
this.x = x;
|
|||
|
this.y = y;
|
|||
|
}
|
|||
|
|
|||
|
var p1 = new Point2D(1, 2);
|
|||
|
console.log(p1.x); // 1
|
|||
|
console.log(p1.y); // 2
|
|||
|
```
|
|||
|
|
|||
|
Lo que debe notar es la función `Point2D` llamada con una `new` palabra clave, y `this` referencia está vinculada al objeto `p1` . Entonces, cuando se llama a una función con una `new` palabra clave, se creará un nuevo objeto y `this` referencia se vinculará a este objeto.
|
|||
|
|
|||
|
Nota: al llamar a una función con una `new` palabra clave, también la llamamos _función constructora_ .
|
|||
|
|
|||
|
### Regla 5
|
|||
|
|
|||
|
JavaScript determina el valor de `this` en tiempo de ejecución, según el contexto actual. Entonces, `this` veces puede apuntar a algo distinto de lo que esperas.
|
|||
|
|
|||
|
Considere este ejemplo de una clase Cat con un método llamado `makeSound()` , siguiendo el patrón en la Regla 4 (arriba) con una función constructora y la `new` palabra clave.
|
|||
|
|
|||
|
```javascript
|
|||
|
var Cat = function(name, sound) {
|
|||
|
this.name = name;
|
|||
|
this.sound = sound;
|
|||
|
this.makeSound = function() {
|
|||
|
console.log( this.name + ' says: ' + this.sound );
|
|||
|
};
|
|||
|
}
|
|||
|
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
|
|||
|
kitty.makeSound(); // Fat Daddy says: Mrrooowww
|
|||
|
```
|
|||
|
|
|||
|
Ahora tratemos de darle al gato una manera de `annoy()` personas repitiendo su sonido 100 veces, una vez cada medio segundo.
|
|||
|
|
|||
|
```javascript
|
|||
|
var Cat = function(name, sound) {
|
|||
|
this.name = name;
|
|||
|
this.sound = sound;
|
|||
|
this.makeSound = function() {
|
|||
|
console.log( this.name + ' says: ' + this.sound );
|
|||
|
};
|
|||
|
this.annoy = function() {
|
|||
|
var count = 0, max = 100;
|
|||
|
var t = setInterval(function() {
|
|||
|
this.makeSound(); // <-- this line fails with `this.makeSound is not a function`
|
|||
|
count++;
|
|||
|
if (count === max) {
|
|||
|
clearTimeout(t);
|
|||
|
}
|
|||
|
}, 500);
|
|||
|
};
|
|||
|
}
|
|||
|
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
|
|||
|
kitty.annoy();
|
|||
|
```
|
|||
|
|
|||
|
Eso no funciona porque dentro de la `setInterval` llamada `setInterval` hemos creado un nuevo contexto con alcance global, por lo que `this` ya no apunta a nuestra instancia de Kitty. En un navegador web, `this` apuntará al objeto Window, que no tiene un método `makeSound()` .
|
|||
|
|
|||
|
Un par de maneras de hacerlo funcionar:
|
|||
|
|
|||
|
1) Antes de crear el nuevo contexto, asigne `this` a una variable local llamada `me` , o `self` , o como se llame, y use esa variable dentro de la devolución de llamada.
|
|||
|
|
|||
|
```javascript
|
|||
|
var Cat = function(name, sound) {
|
|||
|
this.name = name;
|
|||
|
this.sound = sound;
|
|||
|
this.makeSound = function() {
|
|||
|
console.log( this.name + ' says: ' + this.sound );
|
|||
|
};
|
|||
|
this.annoy = function() {
|
|||
|
var count = 0, max = 100;
|
|||
|
var self = this;
|
|||
|
var t = setInterval(function() {
|
|||
|
self.makeSound();
|
|||
|
count++;
|
|||
|
if (count === max) {
|
|||
|
clearTimeout(t);
|
|||
|
}
|
|||
|
}, 500);
|
|||
|
};
|
|||
|
}
|
|||
|
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
|
|||
|
kitty.annoy();
|
|||
|
```
|
|||
|
|
|||
|
2) Con ES6 puede evitar la asignación de `this` a una variable local mediante el uso de una función de flecha, que se une `this` con el contexto del código que rodea donde se define.
|
|||
|
|
|||
|
```javascript
|
|||
|
var Cat = function(name, sound) {
|
|||
|
this.name = name;
|
|||
|
this.sound = sound;
|
|||
|
this.makeSound = function() {
|
|||
|
console.log( this.name + ' says: ' + this.sound );
|
|||
|
};
|
|||
|
this.annoy = function() {
|
|||
|
var count = 0, max = 100;
|
|||
|
var t = setInterval(() => {
|
|||
|
this.makeSound();
|
|||
|
count++;
|
|||
|
if (count === max) {
|
|||
|
clearTimeout(t);
|
|||
|
}
|
|||
|
}, 500);
|
|||
|
};
|
|||
|
}
|
|||
|
var kitty = new Cat('Fat Daddy', 'Mrrooowww');
|
|||
|
kitty.annoy();
|
|||
|
```
|
|||
|
|
|||
|
### Otros recursos
|
|||
|
|
|||
|
* [javascriptissexy.com](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/)
|
|||
|
* [No sabes js](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md)
|