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

1309

Me he dado cuenta de que no parece haber una explicación clara de qué es la thispalabra clave y cómo se usa correcta (e incorrectamente) en JavaScript en el sitio de Stack Overflow.

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

¿Cómo thisfunciona y cuándo debe usarse?

Maxim Gershkovich
fuente
66
Encontré esto cuando busqué en Google "esto" quirksmode.org/js/this.html
Wai Wong
2
Peter Michaux aboga contra el uso de this peter.michaux.ca/articles/javascript-widgets-without-this
Marcel Korpel
1
La visión general MDN no es del todo malo ... developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/...
dat
2
Una explicación interesante de la thispalabra clave: rainsoft.io/gentle-explanation-of-this-in-javascript
Dmitri Pavlutin

Respuestas:

1351

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

Una vez que empiezas a acostumbrarte this, las reglas son bastante simples. El estándar ECMAScript 5.1 define this:

§11.1.1 Elthis palabra clave

La thispalabra clave evalúa el valor de ThisBinding del contexto de ejecución actual

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

1. Contexto de ejecución global inicial

Este es el caso del código JavaScript que se evalúa en el nivel superior, por ejemplo, cuando está directamente dentro de un <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 ).

Introducir 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 la llamada ( §10.4.2 (2) (a)).

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

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

Introducir 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 in obj.myMethod()o el equivalente obj["myMethod"](), ThisBinding se establece en el objeto ( objen el ejemplo; §13.2.1 ). En la mayoría de los otros casos, ThisBinding se establece en el objeto global ( §10.4.3 ).

La razón para escribir "en la mayoría de los otros 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 thisArgque se convierte en ThisBinding cuando se llama 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 las Function.prototypefunciones, se invocan en un objeto de función, pero en lugar de establecer ThisBinding en el objeto de función, ThisBinding se establece en thisArg.

En el caso de las Array.prototypefunciones, lo dado callbackfnse llama en un contexto de ejecución donde ThisBinding se establece thisArgsi se proporciona; de lo contrario, al objeto global.

Esas son las reglas para JavaScript simple. Cuando comience 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 generalmente consideran que este comportamiento es más conveniente. Al pasar funciones de devolución de llamada que hacen referencia thisa funciones de biblioteca, debe consultar la documentación para ver las garantías sobre cuál es el valor de thiscuando se llama a la función.

Si se pregunta cómo una biblioteca de JavaScript manipula el valor de this, la biblioteca simplemente está utilizando una de las funciones de JavaScript incorporadas que aceptan a 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 mencioné. Al construir un nuevo objeto a través del newoperador, 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 de constructor, el valor de thises el nuevo objeto que creó el intérprete:

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

Funciones de flecha

Las funciones de flecha (introducidas en ECMA6) alteran el alcance de this. Vea la pregunta canónica existente, Función de flecha vs declaración / expresiones de función: ¿Son equivalentes / intercambiables? para más información. Pero en resumen:

Las funciones de flecha no tienen su propio this... enlace. En cambio, esos identificadores se resuelven en el ámbito léxico como cualquier otra variable. Eso significa que dentro de una función de flecha, this... se refieren a los valores del thisentorno en el que se define la función de flecha.

Solo por diversión, pruebe su comprensión con algunos ejemplos

Para revelar las respuestas, pase el mouse sobre los cuadros grises claros.

  1. ¿Cuál es el valor de thisen 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 thisen la línea marcada cuando obj.staticFunction()se ejecuta? ¿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 thisen 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 que myFun/ obj.myMethodno se llama en un objeto, ThisBinding se establece en window.

    Esto es diferente de Python, en el que acceder 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 thisen la línea marcada? ¿Por qué?

    window

    Este fue complicado. Al evaluar el código eval, thises obj. Sin embargo, en el código de evaluación, myFunno se llama a un objeto, por lo que ThisBinding está configurado windowpara la llamada.

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

    obj

    La línea myFun.call(obj);invoca la función incorporada especial Function.prototype.call(), que acepta thisArgcomo 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);
      

Daniel Trebbien
fuente
66
@ Ali: Son referencias a secciones dentro de la edición 5.1 del Estándar ECMAScript, ECMA-262 . Se los proporciono para que pueda leer el Estándar para los detalles técnicos si lo desea.
Daniel Trebbien
1
Creo que @supertonsky tiene razón sobre el n. ° 2: si se llama a myFun () desde el alcance global, y no como un método en el objeto, "este" será el objeto global, por lo que la formulación de la pregunta es importante. por cierto, me gusta mucho la idea de usar mouseover para obtener la respuesta para algo como esto.
user655489
2
Pero, jsfiddle.net/H4LYm/2 muestra que el setTimeoutejemplo tiene una thisde window(global).
Kevin Meredith
2
viniendo de Python, uno imaginaría los niveles de frustración que tuve cuando me topé con el tercer ejemplo ... smh
Marius Mucenicu
1
Esta respuesta probablemente debería actualizarse para reflejar la realidad de ES2020, incluso si los cambios son solo terminológicos.
Ben Aston
156

La thispalabra clave se comporta de manera diferente en JavaScript en comparación con otros idiomas. En lenguajes orientados a objetos, la thispalabra clave se refiere a la instancia actual de la clase. En JavaScript, el valor de thisestá determinado por el contexto de invocación de function ( context.function()) y dónde se llama.

1. Cuando se usa en contexto global

Cuando se usa thisen contexto global, está vinculado al objeto global ( windowen el navegador)

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

Cuando se usa thisdentro de una función definida en el contexto global, thistodavía está vinculada al objeto global, ya que la función se convierte en un método de contexto global.

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

Arriba f1se hace un método de objeto global. Por lo tanto, también podemos llamarlo en el windowobjeto de la siguiente manera:

function f()
{
    return this;
}

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

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

Cuando utiliza una thispalabra clave dentro de un método de objeto, thisestá vinculado al objeto que encierra "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 thisestá 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 la función explícitamente al objeto como método, sigue las reglas anteriores, es decir, thisapunta al objeto primario 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. Al invocar la función sin contexto

Cuando utiliza thisuna función interna que se invoca sin ningún contexto (es decir, no en ningún objeto), está vinculada al objeto global ( windowen 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

También podemos probar los puntos anteriores con funciones. Sin embargo, hay algunas diferencias.

  • Arriba agregamos miembros a los objetos usando notación literal de objetos. Podemos agregar miembros a las funciones mediante el uso this. para especificarlos.
  • La notación literal de objeto crea una instancia de objeto que podemos usar de inmediato. Con la función, es posible que primero necesitemos crear su instancia utilizando el newoperador.
  • También en un enfoque literal de objeto, podemos agregar explícitamente miembros a un objeto ya definido utilizando el operador de punto. Esto se agrega solo a la instancia específica. Sin embargo, he agregado una variable al prototipo de la 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 thissuperiores, pero primero creé la función 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 una newpalabra clave), el thiscuerpo interno de la función 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 prototipo de un objeto, thisdentro de dicho método se hace referencia al objeto en el que se llamó al 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. Dentro de las funciones call (), apply () y bind ()

  • 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 thisque se utilizará mientras se ejecuta la función. También toman cualquier parámetro para pasar a la función original cuando se invoca.
  • fun.apply(obj1 [, argsArray])Se establece obj1como el valor de thisinside fun()y llama a los fun()elementos que pasan argsArraycomo sus argumentos.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Establece obj1como el valor de thisinside fun()y llama a fun()pasar arg1, arg2, arg3, ...como sus argumentos.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Devuelve la referencia a la función funcon thisdiversión interna vinculada a obj1y parámetros funvinculados a los parámetros especificados arg1, arg2, arg3,....
  • Por ahora la diferencia entre apply, cally binddebe haberse hecho evidente. applypermite especificar los argumentos para funcionar como un objeto tipo matriz, es decir, un objeto con una lengthpropiedad numérica y propiedades enteras no negativas correspondientes. Mientras que callpermite especificar los argumentos de la función directamente. Ambos applye callinmediatamente invocan la función en el contexto especificado y con los argumentos especificados. Por otro lado, bindsimplemente devuelve la función vinculada al thisvalor especificado 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. thiscontroladores de eventos internos

  • Cuando asigna una función directamente a los manejadores de eventos de un elemento, el uso de la thisfunción de manejo de eventos directamente dentro se refiere al elemento correspondiente. Dicha asignación directa de funciones se puede hacer utilizando el addeventListenermétodo o mediante los métodos tradicionales de registro de eventos como onclick.
  • Del mismo modo, cuando se usa thisdirectamente dentro de la propiedad de evento (like <button onclick="...this..." >) del elemento, se refiere al elemento.
  • Sin embargo, el uso thisindirecto a través de la otra función llamada dentro de la función de manejo de eventos o 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 (efectivamente lo llama 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>

8. thisen la función de flecha ES6

En una función de flecha, thisse comportará como variables comunes: se heredará de su ámbito léxico. Las funciones this, donde se define la función de flecha, serán las funciones de flecha this.

Entonces, ese es el mismo comportamiento que:

(function(){}).bind(this)

Ver el siguiente código:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 
Mahesha999
fuente
"Cuando se usa esto dentro de una función definida en el contexto global, todavía está vinculada al objeto global, ya que la función se convierte en un método de contexto global". Es incorrecto. esto se establece por cómo se llama una función o por enlace , no por dónde se define. Llamar a cualquier función sin una referencia de base ( "contexto") será por defecto esta al objeto global o permanecen indefinidos en modo estricto.
RobG
@RobG hmm puede ser, pero encontré esto en MDN : en este caso, thisla llamada no establece el valor de . Como el código no está en modo estricto, el valor de thissiempre debe ser un objeto, por lo que el valor predeterminado es el objeto global. Y, de hecho, por eso pensé que podíamos hacer una llamada directamente window.f1(), de modo que los medios f1()ya están unidos al windowobjeto, quiero decir antes de la invocación. ¿Me estoy equivocando?
Mahesha999
Estaba comentando (tal vez no claramente) sobre su vinculación de la configuración de esto con "la función en realidad se convierte en un método del contexto global", como si se llamara algo así window.fn, lo que no es. el valor predeterminado es el objeto global porque no se usó ninguna referencia base en la llamada, no por el lugar donde se define la función (por lo tanto, esto todavía se establece por cómo se llamó la función). Si lo llama explícitamente usando window.fn, entonces está configurando esto como ventana . El mismo resultado, una forma diferente de hacerlo. :-)
RobG
"arriba he puesto la palabra inmediata ..." no, no lo hiciste. ¿Puede revisar esto para que se solucione el error? La respuesta parece semántica y, por lo tanto, no puedo seguir leyendo hasta que se solucione el error por temor a aprender algo incorrecto.
TylerH
@TylerH haga Ctrl + F en esta página en su navegador para encontrar la cadena "inmediata" (incluyendo comillas dobles) Creo que está ahí si lo entiendo mal
Mahesha999
64

Javascript this

Invocación de funciones simples

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 thisse registraría como window. Esto se debe a que windowes la variable global en el alcance de un navegador web.

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

Ahora, si ejecutamos esto en modo estricto agregando la declaración "use strict";al comienzo de la declaración de función, thisya no se referiría a la variable global en ninguno de los entornos. Esto se hace para evitar confusiones en modo estricto. thissería, en este caso, simplemente iniciar sesión undefined, porque 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 forEachy slice, ya debería saber que la thisvariable en ese caso se refiere a la función Objectsobre la que llamó a esa función (tenga en cuenta que en javascript, casi todo es an Object, incluidos Arraysy 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 un Objectcontiene una propiedad que contiene un Function, la propiedad se llama un método. Este método, cuando se llama, siempre tendrá su thisvariable configurada con la Objectque está asociada. Esto es cierto para los modos estrictos y no estrictos.

Tenga en cuenta que si un método se almacena (o mejor dicho, se copia) en otra variable, la referencia a thisya no se conserva en la nueva variable. Por ejemplo:

// continuing with the previous code snippet

var myVar = myObj.logThis;
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

La newpalabra clave

Considere una función constructora 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é sucede cuando usamos la newpalabra clave.

  1. Llamar a la función con la newpalabra clave inmediatamente inicializaría un Objecttipo Person.
  2. El constructor de esto Objecttiene su constructor establecido en Person. Además, tenga en cuenta que solo typeof awalvolvería Object.
  3. A esta nueva Objectse le asignaría el prototipo de Person.prototype. Esto significa que cualquier método o propiedad en el Personprototipo estaría disponible para todas las instancias de Person, incluso awal.
  4. La función Personmisma ahora se invoca; thissiendo una referencia al objeto recién construido awal.

Bastante sencillo, ¿eh?

Tenga en cuenta que la especificación oficial de ECMAScript en ninguna parte establece que tales tipos de funciones son constructorfunciones reales . Son funciones normales y newse pueden usar en cualquier función. Es solo que los usamos como tales, por lo que los llamamos solo como tales.

Funciones de llamada en funciones: callyapply

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

Todas las funciones heredan de lo global Function, y dos de sus muchos métodos son cally apply, y ambos pueden usarse para manipular el valor de thisen 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 thisla función foocomo referencia thisArg. Todos los demás parámetros pasados callse pasan a la función foocomo argumentos.
Entonces, el código anterior iniciará sesión {myObj: "is cool"}, [1, 2, 3]en la consola. Muy buena manera de cambiar el valor de thisen cualquier función.

applyes casi lo mismo que callaceptar que solo toma dos parámetros: thisArgy una matriz que contiene los argumentos que se pasarán a la función. Entonces, la callllamada anterior se puede traducir de applyesta manera:

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

Tenga en cuenta que cally applypuede anular el valor de la thisinvocación del método set by dot que discutimos en la segunda viñeta. Suficientemente simple :)

Presentando ... bind!

bindes hermano de cally apply. También es un método heredado por todas las funciones del Functionconstructor global en Javascript. La diferencia entre binde call/ applyes que tanto cally applyen realidad se invoca la función. bind, por otro lado, devuelve una nueva función con el thisArgy argumentspreestablecido. 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 cally apply, bindtambién anulará el valor de thisestablecer por invocación de método de punto.

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

Cosas extra, copia esto

A veces, no le gusta el hecho de que thiscambie 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 thiscambió con el alcance anidado, pero queríamos el valor del thisalcance original. Así que 'copiado' thisa thaty utilizamos la copia en lugar de this. Inteligente, ¿eh?

Índice:

  1. ¿Qué se guarda thispor defecto?
  2. ¿Qué pasa si llamamos a la función como un método con notación de punto-objeto?
  3. ¿Qué pasa si usamos la newpalabra clave?
  4. ¿Cómo manipulamos thiscon cally apply?
  5. Utilizando bind.
  6. Copiar thispara resolver problemas de alcance anidado.
usuario3459110
fuente
47

"esto" tiene que ver con el alcance. Cada función tiene su propio alcance, y dado que todo en JS es un objeto, incluso una función puede almacenar algunos valores en sí misma usando "esto". 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 funciones de cierre anónimas como:

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

Así que aquí, dentro de cada (), "esto" no contiene el "valor" que espera (de

this.value = value;
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 = value;
    $ ('. algunos elementos'). each (function (elt) {
        elt.innerHTML = self.value; // ¡uf! == 2
    });
}) (2);

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

arunjitsingh
fuente
66
"todo en JS es un objeto" no es cierto, JavaScript también tiene valores primitivos, vea bclary.com/2004/11/07/#a-4.3.2
Marcel Korpel
66
Los valores primitivos parecen tener algunos métodos en sí mismos, como String # substring (), Number # toString (), etc. Entonces, tal vez no con la misma nomenclatura que ese artículo, realmente se comportan como si fueran objetos (son todos prototipados, es decir. String # substring () es realmente: String.prototype.substring = function () {...}). Por favor corrígeme si estoy equivocado.
arunjitsingh
12
La thispalabra clave no tiene nada que ver con el alcance. Además, tiene un significado también en funciones que no son propiedades de los objetos.
Bergi
1
@ Arunjitsingh: hay dos escuelas de pensamiento al respecto. Me gusta el que dice " todo es un objeto, pero algunos pueden ser representados por primitivas por conveniencia ". ;-)
RobG
99
thisNo es TODO sobre el alcance. Se trata TODO sobre el contexto de ejecución, que no es lo mismo que el alcance. JavaScript tiene un alcance léxico (lo que significa que el alcance está determinado por la ubicación del código), pero thisestá determinado por cómo se invoca la función que lo contiene, no dónde está esa función.
Scott Marcus
16

Dado que este hilo ha aumentado, he compilado algunos puntos para lectores nuevos en el thistema.

¿Cómo se thisdetermina el valor de ?

Utilizamos esta similar a la forma en que usamos los pronombres en las lenguas naturales como el Inglés: “Juan está ejecutando rápido porque él está tratando de coger 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 se le asigna 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 el windowobjeto. Por lo tanto, thisen una función global se refiere (y tiene el valor de) el windowobjeto global .

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

La thispalabra clave se malinterpreta más cuando: 1) tomamos prestado un método que usa this, 2) asignamos un método que usa thisa una variable, 3) una función que usa thisse pasa como una función de devolución de llamada y 4) thisse usa dentro de un cierre - Una función interna. (2)

mesa

Lo que depara el futuro

Definido en ECMA Script 6 , las funciones de flecha adoptan el thisenlace desde el ámbito de cierre (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!

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


Referencias

  1. this & Object Prototypes , de Kyle Simpson. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2RacU
carlodurso
fuente
16

thisen JavaScript siempre se refiere al 'propietario' de la función que se está ejecutando .

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

Entonces si lo hiciera

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

element.onclick = someKindOfFunction;

thisse referiría al elemento objeto. Pero tenga cuidado, mucha gente comete este error.

<element onclick="someKindOfFunction()">

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

Seph
fuente
15

Cada contexto de ejecución de Javascript tiene un presente que tendrá el parámetro por:

  1. Cómo se llama a la función (incluso como método de objeto, uso de call y apply , uso de new )
  2. Uso de bind
  3. Léxico para las funciones de flecha (adoptan esto de su contexto de ejecución externo)
  4. Si el código está en modo estricto o no estricto
  5. Si el código fue invocado usando eval

Puede establecer el valor de esto usando func.call, func.applyo func.bind.

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

jQuery hace que este cambio sea trivial con jQuery.proxy.

estúpido
fuente
99
Es un poco más correcto decir que cada llamada a función tiene un alcance. En otras palabras, lo que está confuso sobre thisen Javascript es que es no una propiedad intrínseca de la función en sí, sino más bien un artefacto de la forma en que se invoca la función.
Pointy
@pointy gracias. lo que causa la mayor confusión sobre esto en js es el hecho de que en todos los lenguajes utilizados anteriormente (c #, c ++), esto no se puede manipular n siempre apunta a la instancia del objeto, mientras que en js depende y se puede cambiar al invocar funciones usando func.call, func.bindetc. - Sushil
Sushil
2
thisno no hacer referencia ámbito de una función. thishará referencia a un objeto específico (o posiblemente undefined), que como has dicho se puede cambiar usando .call()o .apply(). El alcance de una función es (esencialmente, cuando se simplifica) a qué variables tiene acceso, y esto depende completamente de dónde se declara la función y no se puede cambiar.
nnnnnn
@Pointy: "Es un poco más correcto decir que cada llamada a función tiene un alcance". Aún más correcto decir que las funciones (y ahora los bloques) tienen alcance , las llamadas a funciones tienen contexto . El alcance define cuáles son los identificadores que pueden ser utilizados por el código en ese alcance. El contexto define a qué están vinculados esos identificadores.
TJ Crowder
1
"Cualquiera que sea ese alcance, se hace referencia a" esto "". No, thisy el alcance no tiene nada que ver entre sí en ES5 y antes (por ejemplo, cuando se escribió esta respuesta). En ES2015 (también conocido como ES6), thisy el alcance se relacionan de una manera bastante mínima con las funciones de flecha wrt (la función thisen una flecha se hereda de su alcance adjunto), pero thisnunca se refiere a un alcance.
TJ Crowder
10

Aquí es una buena fuente de thisen JavaScript.

Aquí está el resumen:

  • global esto

    En un navegador, en el ámbito global, thises el windowobjeto

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

    Al nodeusar la respuesta, thises 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

    Al nodeejecutar desde un script, thisen el ámbito global comienza como un objeto vacío. No es lo mismo queglobal

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

Excepto en el caso de los controladores de eventos DOM o cuando thisArgse proporciona un (ver más abajo), tanto en el nodo como en un navegador utilizando thisuna función que no se llama con newreferencias 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 usa use strict;, en cuyo caso thisserá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 se llama a una función con newla thisque será un nuevo contexto, no hará referencia a lo 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 de esto

Las funciones que crea se convierten en objetos de función. Obtienen automáticamente una prototypepropiedad especial , que es algo a lo que puede asignar valores. Cuando crea una instancia al llamar a su función new, obtiene acceso a los valores que asignó a la prototypepropiedad. Accede 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 u objetos en el prototype. Si desea que las instancias tengan sus propios arreglos, créelos 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

Puede usar thiscualquier 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"
  • DOM evento esto

En un controlador de eventos DOM de HTML, thissiempre 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 bindel 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

Dentro de los atributos HTML en los que puede poner JavaScript, thishay 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>
  • evalúa esto

Puedes usar evalpara 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

Puede usar withpara agregar thisal alcance actual para leer y escribir en valores thissin hacer referencia thisexplícita.

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 this

jQuery en muchos lugares se thisreferirá 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>
zangw
fuente
9

Daniel, ¡una explicación asombrosa! Un par de palabras en esta y buena lista de thispuntero de contexto de ejecución en caso de controladores de eventos.

En dos palabras, thisen JavaScript señala el objeto desde el cual (o desde cuyo contexto de ejecución) se ejecutó la función actual y siempre es de solo lectura, no se puede configurar de todos modos (tal intento terminará con 'Inválido a la izquierda lado en el mensaje de la tarea.

Para los controladores de eventos: los controladores de eventos en línea, como <element onclick="foo">, anulan cualquier otro controlador conectado antes y antes, así que tenga cuidado y es mejor mantenerse alejado de la delegación de eventos en línea. Y gracias a Zara Alaverdyan que 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)">
Arman McHitarian
fuente
9

Hay mucha confusión sobre cómo se interpreta "esta" palabra clave en JavaScript. Esperemos que este artículo descanse de una vez por todas. Y mucho más. Por favor lea el artículo completo cuidadosamente. Tenga en cuenta que este artículo es largo.

Independientemente del contexto en el que se utiliza, "this" siempre hace referencia al "objeto actual" en Javascript. Sin embargo, cuál es el "objeto actual" difiere según el contexto . El contexto puede ser exactamente 1 de los 6 siguientes:

  1. Global (es decir, fuera de todas las funciones)
  2. Llamada interna directa de " función no vinculada " (es decir, una función que no se ha vinculado llamando a functionName.bind )
  3. Llamada indirecta interna de "Función no vinculada" a través de functionName.call y functionName.apply
  4. Llamada interna de "Función vinculada " (es decir, una función que se ha vinculado al llamar a functionName.bind )
  5. Mientras que la creación de objetos a través de "nuevo"
  6. Controlador interno de eventos DOM en línea

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 contexto global), el "objeto actual" (y, por lo tanto, el valor de "esto" ) es siempre el objeto "ventana" para los navegadores.

  2. Llamada directa interna "Función no vinculada" :

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

    function UserDefinedFunction(){
        alert(this)
        }

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

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

    En "Modo no estricto", Llamar / Invocar esta función directamente a través de "UserDefinedFunction ()" automáticamente la llamará / invocará como "window.UserDefinedFunction ()" haciendo "window" como el "objeto actual" (y por lo tanto el valor de " esto " ) dentro de " 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", Calling / invocación de la función directamente a través de "UserDefinedFunction ()" será "NO" llamar automáticamente / alegar ésta como "window.UserDefinedFunction ()" .Hence el "objeto actual" (y el valor de "este" ) dentro de "UserDefinedFunction" será indefinido . Invocar esta función en "Modo estricto" dará como resultado lo siguiente

    UserDefinedFunction() // displays undefined

    Sin embargo, invocarlo explícitamente usando un objeto de ventana dará como resultado lo siguiente

    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 se invocó "UserDefinedFunction" a través de o1 , "this" toma el valor de o1 y se muestra el valor de sus propiedades "a" y "b" . El valor de "c" y "d" se mostró como indefinido ya que o1 no define estas propiedades

    De manera similar, cuando se invocó "UserDefinedFunction" a través de o2 , "this" toma el valor de o2 y se muestra el valor de sus propiedades "c" y "d" . El valor de "a" y "b" se muestran como indefinidos como lo hace o2 No define estas propiedades.

  3. Llamada indirecta interior de "Función no vinculada" a través de functionName.call y functionName.apply :

    Cuando se llama a una "Función no vinculada" a través de functionName.call o functionName.apply , el "objeto actual" (y, por lo tanto, el valor de "this" ) se establece en el valor del parámetro "this" (primer parámetro) pasado a la llamada / 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 "Función NO LIGADA" puede modificarse mediante call / apply . Además, si el parámetro "this" no se pasa explícitamente a call / apply , "objeto actual" (y, por lo tanto, el valor de "this") se establece en "window" en modo no estricto y "undefined" en modo estricto.

  4. Llamada interna "Función vinculada " (es decir, una función que se ha vinculado al llamar a functionName.bind ):

    Una función enlazada es una función cuyo "este" valor ha sido fijo. El siguiente código demostró cómo funciona "esto" en caso de función vinculada

    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 vinculada" NO PUEDE ser alterado a través de llamar / aplicar . Además, si el parámetro "this" no se pasa explícitamente a bind, "objeto actual" (y, por lo tanto, el valor de "this" ) se establece en "window" en modo No estricto y "undefined" en modo estricto. Una cosa más. La vinculación de una función ya vinculada no cambia el valor de "esto" . Permanece establecido 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 constructora, el "objeto actual" (y, por lo tanto, el valor de "esto" ) hace referencia al objeto que se está creando actualmente a través de "nuevo", independientemente del estado de enlace de la función. Sin embargo, si el constructor es una función enlazada, se llamará con un conjunto predefinido de argumentos como el conjunto para la función enlazada.

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

    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>

    El "esto" en los ejemplos anteriores se refiere al elemento "botón" y al elemento "div" respectivamente.

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

    En el segundo ejemplo, cuando se hace clic en el elemento "div" , llamará a la función OnDivClick con su segundo parámetro que hace referencia al elemento div en el que se hizo clic. Sin embargo, el valor de "esto" dentro de OnDivClick NO DEBE hacer referencia al elemento div en el que se hizo clic . Se establecerá como el "objeto de ventana" o "indefinido" en No estricto y modos Estricto respectivamente (si OnDivClick es una función independiente ) o se establecerá en un valor Límite predefinido (si OnDivClick es una función vinculada )

A continuación se resume todo el artículo.

  1. En el contexto global "esto" siempre se refiere al objeto "ventana"

  2. Cada vez 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 modo NO estricto y "indefinido" en modo estricto de forma predeterminada.

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

  4. El valor de "esto" dentro de una función no vinculada se puede anular mediante una llamada y aplicar métodos de la función.

  5. El valor de "esto" se fija para una función enlazada y no se puede anular mediante una llamada y aplicar métodos de la función.

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

  7. El valor de "esto" dentro de un constructor es el objeto que se está creando e inicializando

  8. El valor de "this" dentro de un controlador de eventos DOM en línea es una referencia al elemento para el que se proporciona el controlador de eventos.

Arup Hore
fuente
9

Probablemente el artículo más detallado y completo sobre this es el siguiente:

Explicación suave de la palabra clave 'this' en JavaScript

La idea detrás thises comprender que los tipos de invocación de funciones tienen una importancia significativa en la configuración del thisvalor.


Cuando tenga problemas para identificarse this, no se pregunte:

¿De dónde es thistomado ?

pero no preguntarse:

¿Cómo se invoca la función ?

Para una función de flecha (caso especial de transparencia de contexto) pregúntese:

¿Qué valor tiene thisdonde se define la función de flecha ?

Esta mentalidad es correcta cuando se trata thisy le ahorrará dolor de cabeza.

Dmitri Pavlutin
fuente
Además de vincular a su blog, ¿podría profundizar un poco más sobre cómo hacer esas preguntas ayuda a alguien a entender la thispalabra clave?
Magnus Lind Oxlund
7

Esta es la mejor explicación que he visto: Comprenda JavaScripts esto con Clarity

El este referencia SIEMPRE se refiere (y mantiene el valor de) un objeto, un objeto singular, y generalmente se usa dentro de una función o un método, aunque se puede usar fuera de una función en el ámbito global. Tenga en cuenta que cuando usamos el modo estricto, esto tiene el valor de indefinido en funciones globales y en funciones anónimas que no están vinculadas a ningún objeto.

Hay cuatro escenarios en los que esto puede ser confuso:

  1. Cuando pasamos un método (que usa esto ) como argumento para ser utilizado como una función de devolución de llamada.
  2. Cuando usamos una función interna (un cierre). Es importante tener en cuenta que los cierres no pueden acceder a esta variable de la función externa utilizando la palabra clave this porque esta variable solo es accesible por la función en sí, no por las funciones internas.
  3. Cuando un método que se basa en esto se asigna a una variable a través de contextos, en cuyo caso esto hace referencia a otro objeto que no era el originalmente previsto.
  4. Al usar esto junto con los métodos de enlace, aplicación y llamada.

Da ejemplos de código, explicaciones y soluciones, lo que me pareció muy útil.

James Drinkard
fuente
6

En términos seudoclásicos, la forma en que muchas conferencias enseñan la palabra clave 'this' es como un objeto instanciado por una clase o un constructor de objetos. Cada vez que se construye un nuevo objeto a partir de una clase, imagine que debajo del capó se crea y devuelve una instancia local de un objeto 'este'. Recuerdo que enseñó así:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;
mrmaclean89
fuente
5

thises uno de los conceptos mal entendidos en JavaScript porque se comporta de manera poco diferente de un lugar a otro. Simplemente, se thisrefiere al "propietario" de la función que estamos ejecutando actualmente .

thisayuda a obtener el objeto actual (también conocido como contexto de ejecución) con el que trabajamos. Si comprende en qué objeto se ejecuta la función actual, puede comprender fácilmente qué thises la corriente

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Arriba creamos 3 variables con el mismo nombre 'val'. Uno en contexto global, uno dentro de obj y el otro dentro de innerMethod of obj. JavaScript resuelve los identificadores dentro de un contexto particular subiendo la cadena de alcance de local a global.


Pocos lugares donde thisse puedan diferenciar

Llamar a un método de un objeto

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Cuando se ejecuta line1, JavaScript establece un contexto de ejecución (EC) para la llamada a la función, estableciendo thisel objeto al que hace referencia lo que vino antes del último "." . así que en la última línea puedes entender que a()se ejecutó en el contexto global que es el window.

Con constructor

this puede usarse para referirse al objeto que se está creando

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Cuando Person()se ejecuta new, se crea un objeto completamente nuevo. Personse llama y thisse establece para hacer referencia a ese nuevo objeto.

Llamada de función

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

Si omitimos la newpalabra clave, se whatIsThisrefiere al contexto más global que puede encontrar ( window)

Con controladores de eventos.

Si el controlador de eventos está en línea, se thisrefiere al objeto global

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

Al agregar el controlador de eventos a través de JavaScript, se thisrefiere al elemento DOM que generó el evento.


Nipuna
fuente
5

El valor de "esto" depende del "contexto" en el que se ejecuta la función. El contexto puede ser cualquier objeto o el objeto global, es decir, ventana.

Entonces, la semántica de "esto" es diferente de los lenguajes tradicionales de OOP. Y causa problemas: 1. cuando una función se pasa a otra variable (muy probablemente, una devolución de llamada); y 2. cuando se invoca un cierre desde un método miembro de una clase.

En ambos casos, esto se establece en ventana.

Trombo
fuente
3

¿Con qué ayuda esto ? (La mayor confusión de 'esto' en javascript proviene del hecho de que generalmente no está vinculado a su objeto, sino al alcance de ejecución actual, que podría no ser exactamente cómo funciona, pero siempre me parece así) ver el artículo para una explicación completa)

Simon Groenewolt
fuente
1
Sería mejor decir que está vinculado " al contexto de ejecución actual ". Excepto que ES6 (borrador) cambia eso con las funciones de flecha, donde esto se resuelve en el contexto de ejecución externo.
RobG
3

Un poco de información sobre esta palabra clave

Registremos la thispalabra clave en la consola en el ámbito global sin más código pero

console.log(this)

En el cliente / navegador, la this palabra clave es un objeto global que eswindow

console.log(this === window) // true

y

En Server / Node / Javascript runtime la this palabra clave también es un objeto global que esmodule.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Tenga en cuenta que exportses solo una referencia amodule.exports

unclexo
fuente
1

este uso para Scope como este

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

El valor de txt1 y txt es el mismo en el ejemplo anterior $ (this) = $ ('# tbleName tbody tr') es Same

PRADEEP SINGH Chundawat
fuente
1

Tengo una opinión diferente sobre this de las otras respuestas que espero sean útiles.

Una forma de ver JavaScript es ver que solo hay 1 forma de llamar a una función 1 . Está

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

Siempre se proporciona algún valor para objectForThis.

Todo lo demás es azúcar sintáctica para functionObject.call

Entonces, todo lo demás se puede describir por cómo se traduce functionObject.call.

Si solo llama a una función, entonces thises el "objeto global" que en el navegador es la ventana

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

foo();  // this is the window object

En otras palabras,

foo();

fue traducido efectivamente a

foo.call(window);

Tenga en cuenta que si utiliza el modo estricto, entonces thisseráundefined

'use strict';

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

foo();  // this is the window object

lo que significa

En otras palabras,

foo();

fue traducido efectivamente a

foo.call(undefined);

En JavaScript hay operadores como +y -y *. También existe el operador de punto que es.

El .operador cuando se usa con una función a la derecha y un objeto a la izquierda significa efectivamente "pasar objeto comothis a función".

Ejemplo

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

En otras palabras se bar.foo()traduce enconst temp = bar.foo; temp.call(bar);

Tenga en cuenta que no importa cómo se creó la función (principalmente ...). Todo esto producirá los mismos resultados.

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

function otherFunction() { console.log(this) };

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

De nuevo, todos estos son solo azúcar sintáctica para

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

Otra arruga es la cadena prototipo. Cuando usa a.bJavaScript, primero busca en el objeto al que se hace referencia directamente apara la propiedad b. Si bno se encuentra en el objeto, JavaScript buscará en el prototipo del objeto para encontrarlo b.

Hay varias formas de definir el prototipo de un objeto, la más común en 2019 es la classpalabra clave. A los efectos de thisaunque no importa. Lo que importa es que, como se ve en el objeto ade la propiedad bsi encuentra la propiedad ben el objeto o en ella de cadena de prototipo si btermina siendo una función a continuación, las mismas reglas que se aplican por encima. Las breferencias a funciones se llamarán utilizando el callmétodo y pasandoa llamarán como objectForThis como se muestra al principio de esta respuesta.

Ahora. Imaginemos que hacemos una función que se establece explícitamente thisantes de llamar a otra función y luego llamarla con el .operador (punto)

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

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

Siguiendo la traducción a usar call, se obj.bar()convierte const temp = obj.bar; temp.call(obj);. Cuando ingresamos a la barfunción que llamamos, foopero pasamos explícitamente en otro objeto por objectForThis, así que cuando llegamos a foo thises ese objeto interno.

Esto es lo que hacen ambas funciones bindy =>efectivamente. Son más azúcar sintáctica. Construyen efectivamente una nueva función invisible exactamente como la baranterior que se establece explícitamente thisantes de llamar a cualquier función que se especifique. En el caso de bind thisse establece a lo que sea que le pase bind.

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

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

Tenga en cuenta que si functionObject.bindno existiera podríamos hacer el nuestro así

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

y entonces podríamos llamarlo así

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

const bar = bind(foo, {name:'abc'});

Funciones de flecha, el =>operador es azúcar sintáctico para enlace

const a = () => {console.log(this)};

es lo mismo que

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

Al igual que bind, se crea una nueva función invisible que llama a la función dada con un valor enlazado objectForThispero a diferencia binddel objeto a enlazar está implícito. Es lo thisque sea que sea cuando el=> se usa operador.

Entonces, al igual que las reglas anteriores

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()se traduce en lo const temp = obj.foo; temp.call(obj);que significa que el operador de flecha en el interior foose unirá obja una nueva función invisible y devolverá esa nueva función invisible que está asignada b. b()funcionará como siempre tiene b.call(window)o b.call(undefined)llama a la nueva función invisible que foocreó. Esa función invisible ignora lo thispasado y pasa objcomo objectForThis` a la función de flecha.

El código anterior se traduce en

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply es otra función similar acall

functionName.apply(objectForThis, arrayOfArgs);

Pero a partir de ES6 conceptualmente, incluso puede traducir eso en

functionName.call(objectForThis, ...arrayOfArgs);
gman
fuente
0

thisJavascript Resumen :

  • El valor de thisestá determinado por cómo no se invoca la función, dónde se creó.
  • Por lo general, el valor de thisestá determinado por el Objeto que queda del punto. (window en el espacio global)
  • En caso de oyentes, el valor de this refiere al elemento DOM en el que se llamó el evento.
  • Cuando en función se llama con la newpalabra clave, el valor dethis refiere al objeto recién creado
  • Se puede manipular el valor de thislas funciones: call, apply,bind

Ejemplo:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

Ejemplo de oyentes de eventos:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

Constructor de ejemplo:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.

Willem van der Veen
fuente
0

Para comprender "esto" correctamente, uno debe comprender el contexto, el alcance y la diferencia entre ellos.

Alcance : en javascript, el alcance está relacionado con la visibilidad de las variables, el alcance se logra mediante el uso de la función. (Lea más sobre el alcance)

Contexto : el contexto está relacionado con los objetos. Se refiere al objeto al que pertenece una función. Cuando utiliza la palabra clave "this" de JavaScript, se refiere al objeto al que pertenece la función. Por ejemplo, dentro de una función, cuando dice: "this.accoutNumber", se refiere a la propiedad "accoutNumber", que pertenece al objeto al que pertenece esa función.

Si el objeto "myObj" tiene un método llamado "getMyName", cuando la palabra clave JavaScript "this" se usa dentro de "getMyName", se refiere a "myObj". Si la función "getMyName" se ejecutó en el ámbito global, entonces "esto" se refiere al objeto de la ventana (excepto en modo estricto).

Ahora veamos un ejemplo:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

El código de ejecución anterior en la salida del navegador: ingrese la descripción de la imagen aquí

De acuerdo con la salida que se encuentra dentro del contexto del objeto de la ventana, también es visible que el prototipo de la ventana se refiere al Objeto.

Ahora intentemos dentro de una función:

    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>

Salida:

ingrese la descripción de la imagen aquí El resultado es el mismo porque registramos 'esta' variable en el ámbito global y lo registramos en el ámbito funcional, no cambiamos el contexto. En ambos casos, el contexto era el mismo, relacionado con el objeto viuda .

Ahora creemos nuestro propio objeto. En javascript, puede crear un objeto de muchas maneras.

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>

Salida: ingrese la descripción de la imagen aquí

Entonces, a partir del ejemplo anterior, encontramos que 'esta' palabra clave se refiere a un nuevo contexto que está relacionado con myObj, y myObject también tiene una cadena de prototipo para Object.

Vamos a lanzar otro ejemplo:

<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>

salida: tiene sentido ¿verdad? (leer comentarios) ingrese la descripción de la imagen aquí

Si tiene problemas para comprender el ejemplo anterior, intentemos con nuestra propia devolución de llamada;

<script>
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2){
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            }
        }
        var callback2 = function (){
            console.log(this);
        }
        myObj.printName(function(data){
            console.log(data);
            console.log(this);
        }, callback2);
    </script>

salida: ingrese la descripción de la imagen aquí

Ahora, comprendamos Alcance, Self, IIFE y THIS cómo se comporta

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 

La salida es bastante impresionante, ¿verdad? ingrese la descripción de la imagen aquí

Señor
fuente
-1

Respuesta simple:

La palabra clave "this" siempre depende del contexto de invocación. Se mencionan a continuación.

  1. LA FUNCIÓN SE LLAMA CON NUEVA PALABRA CLAVE

    Si se llama a la función con la palabra clave NEW, THIS estará vinculada al objeto recién creado.

    function Car(){
      this.name="BMW";
    }
    const myCar=new Car();
    myCar.name; // output "BMW"

    En lo anterior, esto estará vinculado al objeto 'myCar'

  2. LA FUNCIÓN SE LLAMA EXPLÍCITAMENTE UTILIZANDO MÉTODOS DE LLAMADA Y APLICACIÓN.

    En este caso, THIS estará vinculado al objeto que se pasa explícitamente a la función.

    var obj1={"name":"bond"};
    function printMessage(msg){
        return msg+" "+this.name;
    }
    const message=printMessage.call(obj1,"my name is ");
    console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
  3. SI LA FUNCIÓN SE LLAMA AL OBJETO IMPLÍCITAMENTE, ESTARÁ LIGADO A ESE OBJETO

    var obj1={
       "name":"bond",
        getName: function () {
                    return this.name;
                 }
    };
    const newname=obj1.getName();
    console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
  4. CUANDO LA FUNCIÓN SE LLAMA SIN NINGÚN CONTEXTO, ESTO ESTARÁ LIGADO AL OBJETO GLOBAL

    const util = {
       name: 'Utility',
       getName: function () {
                    return this.name;
    };
    
    const getName=util.getName;
    const newName=getName();
    console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE  BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
  5. EN MODO ESTRICTO ESTO NO SERÁ DEFINIDO

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
PALLAMOLLA SAI
fuente