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) |