2011-02-03 19 views
297

En un archivo JavaScript vi:¿Qué significa 'var that = this;' significa en JavaScript?

function Somefunction(){ 
    var that = this; 
    ... 
} 

Cuál es el propósito de declarar that y asignándole a this?

+3

posible duplicado de [var self = this?] (Http://stackoverflow.com/q/337878/1048572) – Bergi

+2

El truco "this" y "that" no es necesario para las funciones de flecha. Con las funciones de flecha, "esto" funciona como se esperaba. Consulte aquí para obtener más detalles [ES6 en profundidad: funciones de flecha] (https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/) –

+0

aquí se explica el concepto de esto https://scotch.io/@alZami/understanding-this-in-javascript –

Respuesta

428

Estoy ir ing para 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 demostrado esto con jQuery, que sólo es 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 this cambia con frecuencia cuando cambia el ámbito llamando a un nueva función, no puede acceder al valor original utilizándolo. Aliasarlo a that le permite seguir teniendo acceso al valor original de this.

Personalmente, no me gusta el uso de that como alias. Raramente es obvio a lo que se refiere, especialmente si las funciones son más largas que un par de líneas. I siempre usa un alias más descriptivo. En mis ejemplos anteriores, probablemente usaría clickedEl.

+6

Esta respuesta por implementación de ejemplo lo resumió perfectamente para mí. – Chris

+127

Normalmente voy con 'var self = this;'. La palabra 'que' parece implicar que la variable es cualquier cosa PERO' esto'. –

+11

@David Sí, he pensado ** que ** es algo engañoso. Pero si, como dice Crockford, es una convención, es prudente seguir esa ruta. Aunque estoy totalmente de acuerdo contigo, tiene mucho más sentido. –

94

De Crockford

Por convención, hacemos una que variable privada. 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 causa que este sea configurado incorrectamente para las funciones internas.

JS Fiddle

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

UsesThat piensa que es llamado a Dave

UsesThis piensa que es llamado indefinido

+2

Gracias, lo resume bien suficiente para mi. – Chris

+2

Lo leí, no entendí porque no tenía ningún detalle, busqué en Google, encontré esta página. Donde nuevamente estoy apuntado a la misma oración. De ahí el voto a la baja. –

+2

Ese es un punto justo, diría que alguien que no esté familiarizado con JavaScript tendría dificultades para comprender el concepto solo con mi respuesta. Respondí muy brevemente (y me vinculé a la página en la que buscabas en Google ...). Diría que la respuesta de un día solitario es la más clara, aunque igual habría preferido en JS simple en comparación con un ejemplo de jQuery. –

77

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 alcance global. Esto puede ser confuso porque espera que this tenga 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 especialmente un problema cuando se crea una función como un método de un objeto (como car.start en el ejemplo) a continuación, crear 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 interna this 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 funciones jquery). Esta es la razón por la cual se usa el nombre de sonido muy general that. Es una convención fácilmente reconocible para superar un defecto en el lenguaje.

Al igual que El Ronnoco insinúa Douglas Crockford cree que esta es una buena idea.

+5

Supongo que esta es una respuesta más útil que la aceptada. Porque aclara la razón por la cual Crockford ha inventado "eso" mientras que la respuesta sobre jQuery no lo hace. –

+3

Esto es en realidad un mejor ejemplo que la respuesta aceptada. Explica cómo es "un error en la especificación del lenguaje ECMAScript que hace que esto se configure incorrectamente para las funciones internas", dijo Douglas. – kakacii

+1

Puede que quiera corregir la gramática. Sé que es más como un error tipográfico, pero podría confundir a los principiantes de JavaScript, ya que esta pregunta es más de principiante. Quiero decir que debería ser: var car = {}; car.starter = {}; car.start = function() {...} – kakacii

2

Algunas veces this pueden referirse a otro ámbito y referirse a otra cosa, por ejemplo, supongamos que desea llamar a un método constructor dentro de un evento DOM, en este caso this 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 

Demo

La solución anterior se assing this a that entonces podemos y acceder a la propiedad de nombre dentro del método sayHi de that, por lo que este se puede llamar sin problemas dentro de la llamada DOM.

Otra solución es asignar un objeto that vacío y agregarle propiedades y métodos y luego devolverlo. Pero con esta solución perdiste el prototype del constructor.

var Person = function(name) { 
    var that = {}; 
    that.name = name; 
    that.sayHi = function() { 
    alert(that.name); 
    }; 
    return that; 
}; 
7

El uso de that no es realmente necesario si haces una solución 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); 
}; 
2

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 que Puede ver que el valor de esto es dos valores diferentes según el elemento DOM al que se dirige, pero cuando agrega "eso" al código anterior cambia el valor de "este" 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(); 
        } 
       }); 
      } 

     }); 
    });` 

..... $ (que) .css ("background-color", "#" ffe700); // Aquí el valor de "eso" es ".our-work-group> p> a" porque el valor de var that = this; así que aunque estamos en "this" = '.our-work-single-page', aún podemos usar "eso" para manipular el elemento DOM anterior.

Cuestiones relacionadas