Pregunta ¿Cómo funciona la palabra clave "this"?


He notado que no parece haber una explicación clara de lo que this la palabra clave es y cómo se usa correctamente (e incorrectamente) en JavaScript en el sitio de desbordamiento de pila.

He sido testigo de un comportamiento muy extraño con él y no he podido entender por qué ha ocurrido.

Cómo this trabajo y cuando debe ser utilizado?


1071
2018-06-27 13:12


origen


Respuestas:


Recomiendo leer Mike WestArtículo de Alcance en JavaScript (espejo) primero. Es una introducción excelente y amigable a los conceptos de this y cadenas de alcance en JavaScript.

Una vez que comienzas a acostumbrarte this, las reglas son bastante simples. los Estándar ECMAScript 5.1 define this:

§11.1.1 los this palabra clave

los this la palabra clave evalúa el valor de ThisBinding del contexto de ejecución actual

Esta vinculación es algo que el intérprete de JavaScript mantiene a medida que evalúa el código JavaScript, como un registro especial de la CPU que contiene una referencia a un objeto. El intérprete actualiza el ThisBinding cada vez que establece un contexto de ejecución en uno de los tres únicos casos:

1. Contexto de ejecución global inicial

Este es el caso del código JavaScript que se evalúa en el nivel superior, p. cuando directamente dentro de una <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

Al evaluar el código en el contexto de ejecución global inicial, ThisBinding se establece en el objeto global, window (§10.4.1.1)

Ingresando el código de evaluación

  • ... por una llamada directa a eval() ThisBinding no se modifica; es el mismo valor que el ThisBinding del contexto de ejecución de llamada (§10.4.2 (2) (a)).

  • ... si no es por una llamada directa a eval()
    ThisBinding se establece en el objeto global como si ejecutando en el contexto inicial de ejecución global (§10.4.2 (1)).

§15.1.2.1.1 define a qué llamada directa eval() es. Básicamente, eval(...) es una llamada directa, mientras que algo así como (0, eval)(...) o var indirectEval = eval; indirectEval(...); es una llamada indirecta a eval(). Ver La respuesta de Chuckj a (1, eval) ('this') vs eval ('this') en JavaScript? y El ECMA-262-5 de Dmitry Soshnikov en detalle. Capítulo 2. Modo estricto. para cuando puede usar un indirecto eval() llamada.

Ingresando el código de función

Esto ocurre cuando se llama a una función. Si se llama a una función en un objeto, como en obj.myMethod() o el equivalente obj["myMethod"](), luego ThisBinding se establece en el objeto (obj en el ejemplo; §13.2.1) En la mayoría de los demás casos, ThisBinding se establece en el objeto global (§10.4.3)

La razón para escribir "en la mayoría de los demás casos" es porque hay ocho funciones integradas de ECMAScript 5 que permiten especificar ThisBinding en la lista de argumentos. Estas funciones especiales toman un llamado thisArg que se convierte en ThisBinding al llamar a la función (§10.4.3)

Estas funciones incorporadas especiales son:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

En el caso de Function.prototype funciones, se les llama a un objeto de función, pero en lugar de establecer ThisBinding al objeto de función, ThisBinding se establece en thisArg.

En el caso de Array.prototype funciones, el dado callbackfn se llama en un contexto de ejecución donde ThisBinding está configurado para thisArg si se suministra; de lo contrario, al objeto global.

Esas son las reglas para JavaScript simple. Cuando comienza a usar las bibliotecas de JavaScript (por ejemplo, jQuery), puede encontrar que ciertas funciones de la biblioteca manipulan el valor de this. Los desarrolladores de esas bibliotecas de JavaScript hacen esto porque tiende a admitir los casos de uso más comunes, y los usuarios de la biblioteca suelen encontrar este comportamiento más conveniente. Al pasar funciones de devolución de llamada que hacen referencia this a las funciones de la biblioteca, debe consultar la documentación para obtener garantías sobre el valor de this es cuando se llama a la función.

Si se pregunta cómo una biblioteca JavaScript manipula el valor de this, la biblioteca simplemente está utilizando una de las funciones incorporadas de JavaScript que acepta thisArg. Usted también puede escribir su propia función tomando una función de devolución de llamada y thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Hay un caso especial que aún no he mencionado. Al construir un nuevo objeto a través del new operador, el intérprete de JavaScript crea un nuevo objeto vacío, establece algunas propiedades internas y luego llama a la función de constructor en el nuevo objeto. Por lo tanto, cuando se llama a una función en un contexto constructor, el valor de this es el nuevo objeto que el intérprete creó:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Solo por diversión, pon a prueba tu comprensión con algunos ejemplos

Para revelar las respuestas, pase el mouse sobre las casillas amarillas claras.

  1. ¿Cuál es el valor de this en la línea marcada? ¿Por qué?

      window - La línea marcada se evalúa en el contexto de ejecución global inicial.

    if (true) {
        // What is `this` here?
    }
    
  2. ¿Cuál es el valor de this en la línea marcada cuando obj.staticFunction() ¿es ejecutado? ¿Por qué?

      obj - Cuando se llama a una función en un objeto, ThisBinding se establece en el objeto.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. ¿Cuál es el valor de this en la línea marcada? ¿Por qué?

      window

    En este ejemplo, el intérprete de JavaScript ingresa el código de función, pero debido a myFun/obj.myMethod no se llama a un objeto, ThisBinding está configurado para window.  

    Esto es diferente de Python, en el que se accede a un método (obj.myMethod) crea un objeto de método enlazado.

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. ¿Cuál es el valor de this en la línea marcada? ¿Por qué?

      window

    Este fue complicado. Al evaluar el código de evaluación, this es obj. Sin embargo, en el código de evaluación, myFun no se llama a un objeto, por lo que ThisBinding está configurado para window por la llamada

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. ¿Cuál es el valor de this en la línea marcada? ¿Por qué?

      obj

    La línea myFun.call(obj); está invocando la función incorporada especial Function.prototype.call(), que acepta thisArg como el primer argumento.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


1150
2017-07-07 17:32



los this la palabra clave se comporta de manera diferente en JavaScript en comparación con otro idioma. En lenguajes orientados a objetos, this palabra clave se refiere a la instancia actual de la clase. En JavaScript, el valor de this está determinada principalmente por el contexto de invocación de la función (context.function()) y donde se llama.

1. Cuando se usa en contexto global

Cuando usas this en el contexto global, está vinculado al objeto global (windowen el navegador)

document.write(this);  //[object Window]

Cuando usas this dentro de una función definida en el contexto global, this todavía está vinculado al objeto global ya que la función se convierte realmente en un método de contexto global.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Encima f1 se hace un método de objeto global. Por lo tanto, también podemos llamarlo window objeto de la siguiente manera:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Cuando se usa dentro del método del objeto

Cuando usas this palabra clave dentro de un método de objeto, this está ligado al objeto de encierre "inmediato".

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Arriba he puesto la palabra inmediata entre comillas dobles. Es para señalar que si anida el objeto dentro de otro objeto, entonces this está vinculado al padre inmediato.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Incluso si agrega funciones explícitamente al objeto como método, sigue las reglas anteriores, es decir this todavía apunta al objeto principal inmediato.

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Cuando invoca función sin contexto

Cuando usas this función interna que se invoca sin ningún contexto (es decir, no en ningún objeto), está vinculada al objeto global (window en el navegador) (incluso si la función está definida dentro del objeto).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Probándolo todo con funciones

Podemos probar los puntos anteriores con funciones también. Sin embargo, hay algunas diferencias.

  • Arriba, agregamos miembros a los objetos usando la notación literal del objeto. Podemos agregar miembros a las funciones mediante el uso de this. para especificarlos.
  • La notación literal del objeto crea una instancia de objeto que podemos usar inmediatamente. Con la función es posible que tengamos que crear primero su instancia usando new operador.
  • También en un enfoque literal de objeto, podemos agregar explícitamente miembros al objeto ya definido mediante el operador de punto. Esto se agrega a la instancia específica solamente. Sin embargo, he agregado una variable al prototipo de función para que se refleje en todas las instancias de la función.

A continuación probé todas las cosas que hicimos con Object y this más arriba, pero primero creando funciones en lugar de escribir directamente un objeto.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Cuando se usa dentro de la función constructora.

Cuando la función se usa como un constructor (es decir, cuando se llama con new palabra clave), this el cuerpo de la función interna apunta al nuevo objeto que se está construyendo.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Cuando se usa dentro de la función definida en la cadena del prototipo

Si el método está en la cadena de prototipos de un objeto, this dentro de tal método se refiere al objeto sobre el que se invocó el método, como si el método estuviera definido en el objeto.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Funciones de llamada interna (), aplicación () y vinculación ()

  • Todos estos métodos están definidos en Function.prototype.
  • Estos métodos permiten escribir una función una vez e invocarla en un contexto diferente. En otras palabras, permiten especificar el valor de this que se usará mientras la función se está ejecutando. También toman cualquier parámetro para pasar a la función original cuando se invoca.
  • fun.apply(obj1 [, argsArray]) Conjuntos obj1 como el valor de this dentro fun() y llamadas fun() pasando elementos de argsArray como sus argumentos.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Juegos obj1 como el valor de this dentro fun() y llamadas fun() paso arg1, arg2, arg3, ... como sus argumentos.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Devuelve la referencia a la función fun con thisdentro de la diversión obligada a obj1 y parámetros de fun obligado a los parámetros especificados arg1, arg2, arg3,....
  • Por ahora la diferencia entre apply, call y bind debe haberse vuelto aparente apply permite especificar los argumentos para funcionar como un objeto similar a una matriz, es decir, un objeto con un valor numérico length propiedad y propiedades enteras no negativas correspondientes. Mientras call permite especificar los argumentos a la función directamente. Ambos apply y call Invoca de forma inmediata la función en el contexto especificado y con los argumentos especificados. Por otra parte, bind simplemente devuelve la función vinculada a la especificada this valor y los argumentos. Podemos capturar la referencia a esta función devuelta asignándola a una variable y luego podemos llamarla en cualquier momento.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this manejadores de eventos internos

  • Cuando asigna la función directamente a los manejadores de eventos de un elemento, el uso de this directamente dentro de la función de manejo de eventos se refiere al elemento correspondiente. Tal asignación de función directa se puede hacer usando addeventListener método o a través de los métodos tradicionales de registro de eventos como onclick.
  • Del mismo modo, cuando usa this directamente dentro de la propiedad del evento (como <button onclick="...this..." >) del elemento, se refiere al elemento.
  • Sin embargo el uso de this indirectamente a través de la otra función llamada dentro de la función de manejo de eventos o la propiedad de evento se resuelve en el objeto global window.
  • El mismo comportamiento anterior se logra cuando adjuntamos la función al controlador de eventos utilizando el método del modelo de registro de eventos de Microsoft attachEvent. En lugar de asignar la función al controlador de eventos (y al hacer así el método de función del elemento), llama a la función en el evento (llamándolo efectivamente en contexto global).

Recomiendo probar esto mejor en JSFiddle.

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

122
2017-10-26 15:07



Javascript this

Invocación de función simple

Considere la siguiente función:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

Tenga en cuenta que estamos ejecutando esto en el modo normal, es decir, no se utiliza el modo estricto.

Cuando se ejecuta en un navegador, el valor de this sería registrado como window. Esto es porque window es la variable global en el alcance de un navegador web.

Si ejecuta este mismo código en un entorno como node.js, this se referiría a la variable global en tu aplicación.

Ahora si ejecutamos esto en modo estricto agregando el enunciado "use strict"; al comienzo de la declaración de la función, this Ya no se referiría a la variable global en ninguno de los entornos. Esto se hace para evitar confusiones en el modo estricto. this sería, en este caso solo iniciar sesión undefinedporque eso es lo que es, no está definido.

En los siguientes casos, veríamos cómo manipular el valor de this.

Llamar a una función en un objeto

Hay maneras diferentes de hacer esto. Si ha llamado a métodos nativos en Javascript como forEach y slice, ya deberías saber que this variable en ese caso se refiere a la Object en el que llamaste a esa función (ten en cuenta que en javascript, casi todo es un Object, incluyendo Arrays y Functions). Tome el siguiente código, por ejemplo.

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Si una Object contiene una propiedad que contiene un Function, la propiedad se llama un método. Este método, cuando se llama, siempre tendrá su this variable establecida en Object está asociado con. Esto es cierto tanto para los modos estrictos como para los no estrictos.

Tenga en cuenta que si un método se almacena (o más bien, se copia) en otra variable, la referencia a this ya no se conserva en la nueva variable. Por ejemplo:

// continuing with the previous code snippet

var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation

Considerando un escenario más comúnmente práctico:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

los new palabra clave

Considere una función de constructor en Javascript:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

¿Como funciona esto? Bueno, veamos qué pasa cuando usamos el new palabra clave.

  1. Llamar a la función con el new la palabra clave inicializaría inmediatamente una Object de tipo Person.
  2. El constructor de esto Object tiene su constructor configurado para Person. Además, tenga en cuenta que typeof awal volvería Object solamente.
  3. Esta nueva Object se le asignaría el prototipo de Person.prototype. Esto significa que cualquier método o propiedad en el Person prototipo estaría disponible para todas las instancias de Person, incluyendo awal.
  4. La función Person sí mismo ahora se invoca; this siendo una referencia al objeto recién construido awal.

Muy directo, ¿eh?

Tenga en cuenta que la especificación oficial de ECMAScript no indica que tales tipos de funciones son reales constructor funciones. Son solo funciones normales, y new se puede usar en cualquier función. Es solo que los usamos como tales, por lo que los llamamos así.

Funciones de llamada en funciones: call y apply

Así que sí, desde functions son también Objects (y, de hecho, las variables de primera clase en Javascript), incluso las funciones tienen métodos que son ... bueno, las funciones son las mismas.

Todas las funciones heredan de la global Function, y dos de sus muchos métodos son call y apply, y ambos pueden usarse para manipular el valor de this en la función en la que se llaman.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

Este es un ejemplo típico de uso call. Básicamente toma el primer parámetro y establece this en la función foo como una referencia a thisArg. Todos los demás parámetros pasaron a call se pasan a la función foo como argumentos.
Entonces el código de arriba se registrará {myObj: "is cool"}, [1, 2, 3] en la consola Muy buena manera de cambiar el valor de this en cualquier función.

apply es casi lo mismo que call acepta que solo requiere dos parámetros: thisArg y una matriz que contiene los argumentos que se pasarán a la función. Entonces el anterior call la llamada se puede traducir a apply Me gusta esto:

foo.apply(thisArg, [1,2,3])

Tenga en cuenta que call y apply puede anular el valor de this establecido por la invocación del método de punto que discutimos en el segundo punto. Suficientemente simple :)

Presentación.... bind!

bind es un hermano de call y apply. También es un método heredado por todas las funciones del mundo Function constructor en Javascript. La diferencia entre bind y call/apply es que ambos call y apply realmente invocará la función. bind, por otro lado, devuelve una nueva función con el thisArg y arguments programar. Tomemos un ejemplo para comprender mejor esto:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

¿Ves la diferencia entre los tres? Es sutil, pero se usan de manera diferente. Me gusta call y apply, bind también anulará el valor de this establecido por invocación de método de punto.

También tenga en cuenta que ninguna de estas tres funciones cambia la función original. call y apply devolvería el valor de las funciones recién construidas mientras bind devolverá la función recién construida, lista para ser llamada.

Cosas extra, copia esto

A veces, no te gusta el hecho de que this cambios con el alcance, especialmente el alcance anidado. Eche un vistazo al siguiente ejemplo.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

En el código anterior, vemos que el valor de this cambiado con el alcance anidado, pero queríamos el valor de this del alcance original. Entonces 'copiamos' this a that y usó la copia en lugar de this. Clever, ¿eh?

Índice:

  1. Qué se celebra en this ¿por defecto?
  2. ¿Qué pasa si llamamos a la función como un método con notación de Objeto-punto?
  3. ¿Qué pasa si usamos el new ¿palabra clave?
  4. ¿Cómo manipulamos? this con call y apply?
  5. Utilizando bind.
  6. Proceso de copiar this para resolver problemas de alcance anidado

46
2018-06-27 14:10



"esto" tiene que ver con el alcance. Cada función tiene su propio alcance, y como todo en JS es un objeto, incluso una función puede almacenar algunos valores en sí misma usando "this". OOP 101 enseña que "esto" solo es aplicable a instancias de un objeto. Por lo tanto, cada vez que se ejecuta una función, una nueva "instancia" de esa función tiene un nuevo significado de "esto".

La mayoría de las personas se confunden cuando intentan usar "esto" dentro de las funciones de cierre anónimo, como:

(función (valor) {
    this.value = valor;
    $ ('. some-elements'). each (function (elt) {
        elt.innerHTML = this.value; // ¡¡UH oh!! posiblemente indefinido
    });
}) (2);

Así que aquí, dentro de cada (), "esto" no tiene el "valor" que esperas (de

this.value = valor;
 sobre eso). Entonces, para superar este problema (sin juego de palabras), un desarrollador podría:

(función (valor) {
    var self = esto; // pequeño cambio
    self.value = valor;
    $ ('. some-elements'). each (function (elt) {
        elt.innerHTML = self.value; // phew !! == 2
    });
}) (2);

Pruébalo; comenzará a gustarle este patrón de programación


43
2017-10-06 19:46



this en Javascript siempre se refiere al 'propietario' de la función que es ser ejecutado.

Si no se define un propietario explícito, se hace referencia al propietario más alto, el objeto de la ventana.

Entonces si lo hice

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this se referiría al objeto del elemento. Pero ten cuidado, mucha gente comete este error

<element onclick="someKindOfFunction()">

En este último caso, simplemente hace referencia a la función, no la entrega al elemento. Por lo tanto, this se referirá al objeto ventana.


12
2017-10-30 03:58



Dado que este hilo se ha incrementado, he compilado algunos puntos para los lectores nuevos en this tema. 

¿Cómo es el valor de this¿determinado?

Usamos esto similar a la forma en que usamos pronombres en idiomas naturales como el inglés: "John está corriendo rápido porque él está tratando de tomar el tren. "En cambio, podríamos haber escrito" ... John está tratando de tomar el tren ".

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this  no tiene asignado un valor hasta que un objeto invoca la función donde está definido. En el ámbito global, todas las variables y funciones globales se definen en window objeto. Por lo tanto, this en una función global se refiere a (y tiene el valor de) el global window objeto.

Cuando use strict, this en funciones globales y anónimas que no están vinculadas a ningún objeto tiene un valor de undefined.

los this la palabra clave es más mal entendido cuando: 1) tomamos prestado un método que usa this, 2) asignamos un método que usa this a una variable, 3) una función que utiliza this se pasa como una función de devolución de llamada, y 4) this se usa dentro de un cierre, una función interna. (2)

table

Lo que sostiene el futuro

Definido en ECMA Script 6, arrow-functions adopta el this vinculante de la encerrando alcance (función o global).

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Mientras que las funciones de flecha proporcionan una alternativa al uso bind(), es importante tener en cuenta que esencialmente están deshabilitando el tradicional this mecanismo a favor de un alcance léxico más ampliamente entendido. (1)


Referencias

  1. este y Object Prototypes, por Kyle Simpson. 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX 
  3. Angus Croll - http://goo.gl/Z2RacU 

12
2018-06-27 13:15



Cada función  contexto de ejecución en javascript tiene un alcance  contexto  esta parámetro que se establece por:

  1. Cómo se llama a la función (incluido como método de objeto, uso de llamada y aplicar, uso de nuevo)
  2. Uso de enlazar
  3. Léxicamente para las funciones de flecha (adoptan el esta de su contexto de ejecución externa)

Cualquiera que sea el contexto del alcance, se hace referencia a "esto".

Usted puede cambia eso establecer el valor de esta  alcance  contexto utilizando func.call, func.apply o func.bind.

Por defecto, y lo que confunde a la mayoría de los principiantes, cuando llamar de vuelta se llama al oyente después de que se genera un evento en un elemento DOM, el contexto del alcance  esta el valor de la función es el elemento DOM.

jQuery hace que esto sea trivial para cambiar con jQuery.proxy.


9
2017-11-29 06:01



aquí es una buena fuente de this en JavaScript.

Aquí está el resumen:

  • global esto

    En un navegador, en el alcance global, this es el windowobjeto

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"
    

    En node usando el repl, this es el espacio de nombres superior. Puedes referirte a él como global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true
    

    En node ejecutando desde un script, this en el alcance global comienza como un objeto vacío. No es lo mismo que global

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
    
  • Funciona esto

Excepto en el caso de controladores de eventos DOM o cuando thisArg se proporciona (ver más abajo), tanto en el nodo como en un navegador usando thisen una función que no se llama con new hace referencia al alcance global ...

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Si utiliza use strict;, en ese caso this estarán undefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Si llamas a una función con new el this será un nuevo contexto, no hará referencia a la global this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • prototipo esto

Las funciones que crea se convierten en objetos de función. Obtienen automáticamente un especial prototype propiedad, que es algo a lo que puedes asignar valores. Cuando crea una instancia llamando a su función con new tienes acceso a los valores que asignaste al prototype propiedad. Accedes a esos valores usando this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Por lo general, es un error asignar matrices o objetos sobre el prototype. Si desea que cada instancia tenga sus propias matrices, créelas en la función, no en el prototipo.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • objetar esto

Puedes usar this en cualquier función en un objeto para referirse a otras propiedades en ese objeto. Esto no es lo mismo que una instancia creada con new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • Evento DOM esto

En un controlador de eventos HTML DOM, this siempre es una referencia al elemento DOM al que se adjuntó el evento

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

A menos que usted bind el contexto

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML esto

Atributos de HTML dentro de los cuales puede poner JavaScript this es una referencia al elemento.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • evaluar esto

Puedes usar eval acceder this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • con este

Puedes usar with agregar this al alcance actual para leer y escribir en valores en this sin referirse a this explícitamente.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery esto

el jQuery en muchos lugares tendrá this referirse a un elemento DOM.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

7
2018-04-23 12:57



Daniel, increíble explicación! Un par de palabras sobre esto y una buena lista de this puntero de contexto de ejecución en caso de manejadores de eventos.

En dos palabras, this en JavaScript señala el objeto a partir del cual (o desde cuyo contexto de ejecución) se ejecutó la función actual y siempre es de solo lectura, no puede establecerlo de todos modos (dicho intento terminará con 'lado izquierdo no válido en la asignación') mensaje.

Para los controladores de eventos: controladores de eventos en línea, como <element onclick="foo">, anule cualquier otro manejador adjunto anteriormente y antes, así que tenga cuidado y es mejor mantenerse fuera de la delegación de evento en línea. Y gracias a Zara Alaverdyan quien me inspiró a esta lista de ejemplos a través de un debate disidente :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

6
2018-01-31 08:29



Hay mucha confusión con respecto a cómo "esta" la palabra clave se interpreta en JavaScript. Esperemos que este artículo los deje descansar de una vez por todas. Y mucho más. Por favor, lea el artículo completo con cuidado. Se advirtió que este artículo es largo.

Independientemente del contexto en el que se utiliza, "esta" siempre hace referencia al "objeto actual" en Javascript. Sin embargo, lo que "objeto actual" es diferente según contexto. los contexto puede ser exactamente 1 de los 6 siguiendo:

  1. Global (es decir, fuera de todas las funciones)
  2. Llamada directa dentro de la función "Sin límite" (es decir, una función que tiene no ha sidoobligado por llamar functionName.bind)
  3. Llamada indirecta "función no vinculada" indirecta mediante functionName.call y functionName.apply
  4. Llamada "Bound Function" en el interior (es decir, una función que ha sido atado llamando functionName.bind)
  5. Mientras que la creación de objetos a través de "nuevo"
  6. Controlador interno de eventos en línea DOM

A continuación, se describe cada uno de estos contextos uno por uno:

  1. Contexto global (es decir, fuera de todas las funciones):

    Fuera de todas las funciones (es decir, en el contexto global) "corriente objeto" (y de ahí el valor de "esta") es siempre el "ventana" objeto para navegadores.

  2. Llamada directa dentro de la función "Sin límite":

    Dentro de una llamada directa de "función no limitada", el objeto que invocado la llamada de función se convierte en el "objeto actual" (y por lo tanto El valor de "esta") Si se llama a una función sin un explícito objeto actual, el objeto actual es el "ventana" objeto (para el modo no estricto) o indefinido (Para el modo estricto). Cualquier función (o variable) definida en Contexto global se convierte automáticamente en propiedad de "ventana" objeto. Por ejemplo, supongamos que la función se define en el contexto global como

    function UserDefinedFunction(){
        alert(this)
        }
    

    se convierte en propiedad del objeto ventana, como si hubiera definido como

    window.UserDefinedFunction=function(){
      alert(this)
    }  
    

    En "Modo no estricto", Llamar / Invocar esta función directamente a través de "UserDefinedFunction ()" llamará / invocará automáticamente como "window.UserDefinedFunction ()" fabricación "ventana" como el "objeto actual" (y de ahí el valor de "esta") dentro "UserDefinedFunction". Invocar esta función en "Modo no estricto" dará como resultado lo siguiente

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()
    

    En "Modo estricto", Llamar / Invocar la función directamente a través de "UserDefinedFunction ()" será "NO" llamarlo / invocarlo automáticamente como "window.UserDefinedFunction ()".Por lo tanto, la "corriente objeto" (y el valor de "esta") dentro "UserDefinedFunction" será indefinido. Invocar esta función en "Modo estricto" dará como resultado lo siguiente

    UserDefinedFunction() // displays undefined
    

    Sin embargo, invocarlo explícitamente utilizando el objeto ventana dará como resultado el seguimiento

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."
    

    Veamos otro ejemplo. Por favor mira el siguiente código

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4
    

    En el ejemplo anterior vemos que cuando "UserDefinedFunction" estaba invocado a través de o1, "esta" toma valor de o1 y el valor de sus propiedades "un" y "segundo" mostrarse. El valor de "do" y "re" se mostraron como indefinido como o1 hace no definir estas propiedades

    Similarmente cuando "UserDefinedFunction" fue invocado a través de o2, "esta" toma valor de o2 y el valor de sus propiedades "do" y "re" obtener display.The valor de "un" y "segundo" se mostraron como indefinido como o2 no define estas propiedades.

  3. Llamada indirecta "función no vinculada" indirecta mediante functionName.call y functionName.apply:

    Cuando un "Función no limitada" se llama a través de functionName.call o functionName.apply, el "objeto actual" (y de ahí el valor de "esta") se establece en el valor de "esta" parámetro (primer parámetro) pasado a llamar / aplicar. El siguiente código demuestra lo mismo.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined
    

    El código anterior muestra claramente que el valor "this" para cualquier "NON" Bound Function "puede ser alterado a través de llamar / aplicar. Además, si el "esta" parámetro no se pasa explícitamente a llamar / aplicar, "objeto actual" (y de ahí el valor de "esto") está configurado para "ventana" en modo no estricto y "indefinido" en modo estricto

  4. Llamada "Bound Function" en el interior (es decir, una función que ha sido vinculada por llamada functionName.bind)

    Una función vinculada es una función cuya "esta" valor ha sido fijo. El siguiente código demostró cómo "esta" funciona en el caso de la función límite

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
    

    Como se indica en el código anterior, "este" valor para cualquier "Función de límite" NO PUEDE ser alterado mediante llamada / solicitud. Además, si el "esta" el parámetro no se pasa explícitamente a bind, "objeto actual" (y de ahí el valor de "esta" ) se establece en "ventana" en Non modo estricto y "indefinido" en modo estricto Una cosa más. La vinculación de una función ya consolidada no cambia el valor de "esta". Permanece configurado como el valor establecido por la primera función de enlace.

  5. Mientras que la creación de objetos a través de "nuevo":

    Dentro de una función de constructor, "objeto actual" (y de ahí el valor de "esta") hace referencia al objeto que se está creando actualmente mediante "nuevo" independientemente del estado de enlace de la función. sin embargo si el constructor es una función enlazada se llamará con conjunto predefinido de argumentos como se establece para la función enlazada.

  6. Controlador interno de eventos en línea DOM:

    Mire el siguiente fragmento de HTML

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
    

    los "esta" en los ejemplos anteriores se refieren al elemento "botón" y al elemento "div" respectivamente.

    En el primer ejemplo, el color de la fuente del botón se establecerá en blanco cuando se hace clic.

    En el segundo ejemplo cuando el "div" elemento se hace clic en él llama a OnDivClick función con su segundo parámetro haciendo referencia al elemento div cliqueado. Sin embargo, el valor de "esta" dentro de OnDivClick NO DEBERÁ referencia el clic div elemento. Se establecerá como el "objeto de ventana" o "indefinido" en No estricto y Modos estrictos respectivamente (si OnDivClick es un función libre) o establecer a un predefinido Valor encuadernado (si OnDivClick es un función ligada)

A continuación se resume todo el artículo

  1. En contexto global "esta" siempre se refiere a la "ventana" objeto

  2. Siempre que se invoca una función, se invoca en el contexto de un objeto ("objeto actual") Si el objeto actual no se proporciona explícitamente, el objeto actual  es el "objeto de ventana" en NO ESTRICTO Modo y "indefinido" en modo estricto por defecto.

  3. El valor de "esta" dentro de una función no limitada es la referencia al objeto en el contexto del cual se invoca la función ("objeto actual")

  4. El valor de "esta" dentro de una función no limitada puede ser anulada por llamada y aplicar métodos de la función.

  5. El valor de "esta" se fija para una función de límite y no se puede anulado por llamada y aplicar métodos de la función.

  6. La función de enlace y ya encuadernada no cambia el valor de "esto". Permanece configurado como el valor establecido por la primera función de enlace.

  7. El valor de "esta" dentro de un constructor es el objeto que se está creado e inicializado

  8. El valor de "esta" dentro de un manejador de eventos DOM en línea es referencia al elemento para el cual se administra el controlador de eventos.


6
2017-11-08 12:17