En un archivo de JavaScript vi:
function Somefunction(){
var that = this;
...
}
¿Cuál es el propósito de declarar that
y asignarle this
esto?
En un archivo de JavaScript vi:
function Somefunction(){
var that = this;
...
}
¿Cuál es el propósito de declarar that
y asignarle this
esto?
Respuestas:
Voy a comenzar esta respuesta con una ilustración:
var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
// this is a reference to the element clicked on
var that = this;
colours.forEach(function() {
// this is undefined
// that is a reference to the element clicked on
});
});
Mi respuesta originalmente demostró esto con jQuery, que es muy ligeramente diferente:
$('#element').click(function(){
// this is a reference to the element clicked on
var that = this;
$('.elements').each(function(){
// this is a reference to the current element in the loop
// that is still a reference to the element clicked on
});
});
Debido a que con this
frecuencia cambia cuando cambia el alcance llamando a una nueva función, no puede acceder al valor original al usarlo. Aliasing to le that
permite todavía acceder al valor original de this
.
Personalmente, no me gusta el uso de that
alias. Raramente es obvio a qué se refiere, especialmente si las funciones son más largas que un par de líneas. Yo siempre uso un alias más descriptivo. En mis ejemplos anteriores, probablemente usaría clickedEl
.
var self = this;
. La palabra that
parece implicar que la variable es cualquier cosa PERO this
.
forEach
función toma un segundo argumento opcional que es el enlace de la función. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);
Por lo tanto, se debe agregar una nota que realmentevar that = this
no se necesita con . forEach
De Crockford
Por convención, hacemos una privada que variable. Esto se utiliza para hacer que el objeto esté disponible para los métodos privados. Esta es una solución para un error en la especificación del lenguaje ECMAScript que hace que esto se configure incorrectamente para las funciones internas.
function usesThis(name) {
this.myName = name;
function returnMe() {
return this; //scope is lost because of the inner function
}
return {
returnMe : returnMe
}
}
function usesThat(name) {
var that = this;
this.myName = name;
function returnMe() {
return that; //scope is baked in with 'that' to the "class"
}
return {
returnMe : returnMe
}
}
var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
"UsesThis thinks it's called " + usesthis.returnMe().myName);
Esto alerta ...
Usos que piensa que se llama Dave
Usos Esto cree que se llama indefinido
that
variable no se usa en absoluto en su ejemplo. Hace que parezca que solo crear una retención variable this
hace algo al resto del código.
Este es un truco para hacer que las funciones internas (funciones definidas dentro de otras funciones) funcionen más como deberían. En javascript, cuando define una función dentro de otra this
, se establece automáticamente en el ámbito global. Esto puede ser confuso porque espera this
tener el mismo valor que en la función externa.
var car = {};
car.starter = {};
car.start = function(){
var that = this;
// you can access car.starter inside this method with 'this'
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to the global scope
// 'this.starter' is undefined, so we use 'that' instead.
that.starter.active = true;
// you could also use car.starter, but using 'that' gives
// us more consistency and flexibility
};
activateStarter();
};
Esto es específicamente un problema cuando crea una función como método de un objeto (como car.start
en el ejemplo) y luego crea una función dentro de ese método (como activateStarter
). En el método de nivel superior this
apunta al objeto, es un método de (en este caso car
) pero en la función internathis
ahora apunta al alcance global. Esto es un dolor
Crear una variable para usar por convención en ambos ámbitos es una solución para este problema muy general con JavaScript (aunque también es útil en las funciones de jquery). Es por eso que el nombre que suena muy generalthat
se usa el . Es una convención fácilmente reconocible para superar una deficiencia en el idioma.
Al igual que El Ronnoco insinúa que Douglas Crockford cree que es una buena idea.
El uso de that
no es realmente necesario si realiza una solución alternativa con el uso de call()
o apply()
:
var car = {};
car.starter = {};
car.start = function(){
this.starter.active = false;
var activateStarter = function(){
// 'this' now points to our main object
this.starter.active = true;
};
activateStarter.apply(this);
};
A veces this
puede referirse a otro ámbito y a otra cosa, por ejemplo, suponga que desea llamar a un método constructor dentro de un evento DOM, en este casothis
se referirá al elemento DOM, no al objeto creado.
HTML
<button id="button">Alert Name</button>
JS
var Person = function(name) {
this.name = name;
var that = this;
this.sayHi = function() {
alert(that.name);
};
};
var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad
La solución anterior voluntad assing this
a that
continuación, podemos y acceso a la propiedad de nombre dentro de lasayHi
método dethat
, por lo que este puede ser llamado sin problemas dentro de la llamada DOM.
Otra solución es asignar un that
objeto vacío y agregarle propiedades y métodos y luego devolverlo. Pero con esta solución perdiste la prototype
del constructor.
var Person = function(name) {
var that = {};
that.name = name;
that.sayHi = function() {
alert(that.name);
};
return that;
};
Aquí hay un ejemplo `
$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'.
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
Por lo tanto, puede ver que el valor de esto es dos valores diferentes dependiendo del elemento DOM al que apunta, pero cuando agrega "eso" al código anterior, cambia el valor de "esto" al que apunta.
`$(document).ready(function() {
var lastItem = null;
$(".our-work-group > p > a").click(function(e) {
e.preventDefault();
var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
if (item == lastItem) {
lastItem = null;
var that = this;
$('.our-work-single-page').show();
} else {
lastItem = item;
$('.our-work-single-page').each(function() {
***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
var imgAlt = $(this).find('img').attr('alt');
if (imgAlt != item) {
$(this).hide();
} else {
$(this).show();
}
});
}
});
});`
..... $ (that) .css ("color de fondo", "# ffe700"); // Aquí el valor de "that" es ".our-work-group> p> a" porque el valor de var that = this; así que aunque estemos en "this" = '.our-work-single-page', aún podemos usar "that" para manipular el elemento DOM anterior.