Cómo acceder al `esto` correcto dentro de una devolución de llamada

1664

Tengo una función constructora que registra un controlador de eventos:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

Sin embargo, no puedo acceder a la datapropiedad del objeto creado dentro de la devolución de llamada. Parece que thisno se refiere al objeto que se creó, sino a otro.

También intenté usar un método de objeto en lugar de una función anónima:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

pero presenta los mismos problemas.

¿Cómo puedo acceder al objeto correcto?

4
2058

Lo que deberías saber sobre this

this(también conocido como "el contexto") es una palabra clave especial dentro de cada función y su valor solo depende de cómo se llamó a la función, no cómo / cuándo / dónde se definió. No se ve afectado por los ámbitos léxicos como otras variables (a excepción de las funciones de flecha, ver más abajo). Aquí hay unos ejemplos:

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

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

Para obtener más información this, consulte la documentación de MDN .


Cómo referirse a la correcta this

Usar funciones de flecha

ECMAScript 6 introdujo las funciones de flecha , que se pueden considerar como funciones lambda. No tienen su propia thisatadura. En cambio, thisse busca en el alcance como una variable normal. Eso significa que no tiene que llamar .bind. Ese no es el único comportamiento especial que tienen, consulte la documentación de MDN para obtener más información.

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

No use this

En realidad, no desea acceder thisen particular, sino al objeto al que se refiere . Es por eso que una solución fácil es simplemente crear una nueva variable que también se refiera a ese objeto. La variable puede tener cualquier nombre, pero los más comunes son selfy that.

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

Dado que selfes una variable normal, obedece a las reglas de alcance léxico y es accesible dentro de la devolución de llamada. Esto también tiene la ventaja de que puede acceder al thisvalor de la devolución de llamada en sí.

Establecimiento explícito thisde la devolución de llamada - parte 1

Puede parecer que no tiene control sobre el valor de thisporque su valor se establece automáticamente, pero ese no es el caso.

Cada función tiene el método .bind [docs] , que devuelve una nueva función thisvinculada a un valor. La función tiene exactamente el mismo comportamiento que la que solicitó .bind, solo que thisusted la configuró. No importa cómo o cuándo se llame a esa función, thissiempre se referirá al valor pasado.

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

En este caso, estamos vinculando las devoluciones de llamada thisal valor de MyConstructor's this.

Nota: Cuando sea un contexto de enlace para jQuery, use jQuery.proxy [docs] en su lugar. La razón para hacer esto es que no necesita almacenar la referencia a la función al desvincular una devolución de llamada de evento. jQuery maneja eso internamente.

Conjunto thisde devolución de llamada - parte 2

Algunas funciones / métodos que aceptan devoluciones de llamada también aceptan un valor al que thisdeben referirse las devoluciones de llamada . Esto es básicamente lo mismo que vincularlo usted mismo, pero la función / método lo hace por usted. Array#map [docs] es un método de este tipo. Su firma es:

array.map(callback[, thisArg])

El primer argumento es la devolución de llamada y el segundo argumento es el valor al que se thisdebe hacer referencia. Aquí hay un ejemplo artificial:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

Nota:this En la documentación de esa función / método se suele mencionar si puede o no pasar un valor . Por ejemplo, el $.ajaxmétodo de jQuery [docs] describe una opción llamada context:

This object will be made the context of all Ajax-related callbacks.


Problema común: uso de métodos de objeto como devoluciones de llamada / controladores de eventos

Otra manifestación común de este problema es cuando se utiliza un método de objeto como controlador de eventos / devolución de llamada. Las funciones son ciudadanos de primera clase en JavaScript y el término "método" es solo un término coloquial para una función que es un valor de una propiedad de objeto. Pero esa función no tiene un enlace específico a su objeto "contenedor".

Considere el siguiente ejemplo:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

La función this.methodse asigna como controlador de eventos de clic, pero si document.bodyse hace clic en, el valor registrado será undefined, porque dentro del controlador de eventos, se thisrefiere a document.body, no a la instancia de Foo.
Como ya se mencionó al principio, a qué se thisrefiere depende de cómo se llame a la función , no de cómo se defina .
Si el código fuera como el siguiente, podría ser más obvio que la función no tiene una referencia implícita al objeto:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

La solución es la misma que se mencionó anteriormente: si está disponible, use .bindpara enlazar explícitamente thisa un valor específico

document.body.onclick = this.method.bind(this);

o llamar explícitamente a la función como un "método" del objeto, mediante el uso de una función anónima como devolución de llamada / controlador de eventos y asignar el objeto ( this) a otra variable:

var self = this;
document.body.onclick = function() {
    self.method();
};

o use una función de flecha:

document.body.onclick = () => this.method();
20
  • 48
    Felix, he leído esta respuesta antes, pero nunca respondí. Me preocupa que la gente use selfy se thatrefiera this. Me siento así porque thises una variable sobrecargada que se usa en diferentes contextos; mientras que selfgeneralmente corresponde a la instancia local y thatgeneralmente se refiere a otro objeto. Sé que no estableciste esta regla, ya que la he visto aparecer en varios otros lugares, pero también es la razón por la que comencé a usarla _this, pero no estoy seguro de cómo se sienten los demás, a excepción de la práctica no uniforme. que ha resultado.
    vol7ron
    12 de septiembre de 2014 a las 15:39
  • 3
    @FelixKling, ¿sería seguro asumir que el uso de estas funciones de prototipo interno siempre tendrá el comportamiento esperado independientemente de cómo se llamen (normalmente)? Cuando se utilizan devoluciones de llamada dentro de funciones de prototipo, ¿hay alguna alternativa a bind (), self o eso?
    andig
    28/12/15 a las 15:57
  • 6
    @FelixKling En ocasiones puede ser útil confiar en Function.prototype.call ()y Function.prototype.apply (). Particularmente con apply ()he conseguido mucho kilometraje. Estoy menos inclinado a usar bind ()quizás solo por costumbre, aunque soy consciente (pero no estoy seguro) de que puede haber ligeras ventajas generales al usar bind sobre las otras opciones.
    Nolo
    15 de nov. De 2016 a las 6:02
  • 5
    Excelente respuesta, pero considere agregar una solución opcional adicional que es simplemente no usar clases, nuevas o esto en absoluto. 12 feb 2017 a las 12:53
  • 4
    re funciones de flecha "En cambio, esto se busca en el alcance como una variable normal". hizo este clic totalmente para mí, ¡gracias! () => this.clicked();) 25 de mayo de 2018 y 20:36
244

Aquí hay varias formas de acceder al contexto principal dentro de un contexto secundario:

  1. Puede utilizar la bind()función.
  2. Almacene una referencia al contexto / esto dentro de otra variable (vea el ejemplo a continuación).
  3. Utilice las funciones de flecha ES6 .
  4. Modifique el código, el diseño de funciones y la arquitectura; para ello, debe tener dominio sobre los patrones de diseño en JavaScript.

1. Utilice la bind()función

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

Si está utilizando Underscore.js: http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2. Almacene una referencia al contexto / esto dentro de otra variable

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3. Función de flecha

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
2
  • 1
    La opción bind () es increíble, solo pasa el puntero de este objeto para que sea este en el otro objeto (: ¡Gracias! 13/03/19 a las 11:31
  • " ... el contexto de los padres dentro de contexto de la niñez " es una frase engañosa ya que este no es parte de una relación padre / hijo. A menudo se refiere al objeto al que se llamó un método, pero puede ser cualquier objeto o cualquier valor en modo estricto. " Contexto " se refiere a un contexto de ejecución (del cual este es un parámetro de muchos) al que no se puede hacer referencia porque ECMA-262 lo prohíbe.
    RobG
    29 de marzo a las 9:23
69

Todo está en la sintaxis "mágica" de llamar a un método:

object.property();

Cuando obtiene la propiedad del objeto y lo llama de una vez, el objeto será el contexto del método. Si llama al mismo método, pero en pasos separados, el contexto es el alcance global (ventana) en su lugar:

var f = object.property;
f();

Cuando obtienes la referencia de un método, ya no está adjunto al objeto. Es solo una referencia a una función simple. Lo mismo sucede cuando obtiene la referencia para usar como devolución de llamada:

this.saveNextLevelData(this.setAll);

Ahí es donde vincularía el contexto a la función:

this.saveNextLevelData(this.setAll.bind(this));

Si está usando jQuery, debe usar el $.proxymétodo en su lugar, ya bindque no es compatible con todos los navegadores:

this.saveNextLevelData($.proxy(this.setAll, this));
42

Usted debe saber sobre palabra "this".

Según mi punto de vista, puede implementar "esto" de tres maneras (función Auto / Flecha / Método de vinculación)

La thispalabra clave de una función se comporta un poco diferente en JavaScript en comparación con otros lenguajes.

También tiene algunas diferencias entre el modo estricto y el modo no estricto.

En la mayoría de los casos, el valor de esto está determinado por cómo se llama a una función.

No se puede configurar por asignación durante la ejecución y puede ser diferente cada vez que se llama a la función.

ES5 introdujo el método bind () para establecer el valor de una función thisindependientemente de cómo se llame,

Y ES2015 introdujo funciones de flecha que no proporcionan su propio thisenlace (retiene este valor del contexto léxico adjunto).

Método 1: Self - Self se está utilizando para mantener una referencia al original, incluso cuando el contexto está cambiando. Es una técnica que se usa a menudo en controladores de eventos (especialmente en cierres).

Referencia : este

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

Método 2 : función de flecha: una expresión de función de flecha es una alternativa sintácticamente compacta a una expresión de función regular, aunque sin sus propios enlaces a las palabras clave this, argumentos, super o new.target.

Las expresiones de función de flecha no son adecuadas como métodos y no se pueden usar como constructores.

Referencia : expresiones de función de flecha

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

Método 3 : Bind: el método bind () crea una nueva función que, cuando se llama, tiene su thispalabra clave establecida en el valor proporcionado con una secuencia dada de argumentos que preceden a los proporcionados cuando se llama a la nueva función.

Referencia: Function.prototype.bind ()

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);
36

El problema con el "contexto"

El término "contexto" se utiliza a veces para referirse al objeto al que hace referencia este . Su uso es inadecuado, porque no encaja bien semánticamente o técnicamente con ECMAScript de este .

"Contexto" significa las circunstancias que rodean algo que agrega significado, o alguna información anterior y siguiente que le da un significado adicional. El término "contexto" se usa en ECMAScript para referirse al contexto de ejecución , que son todos los parámetros, alcance y esto dentro del alcance de algún código de ejecución.

Esto se muestra en ECMA-262 sección 10.4.2 :

Set the ThisBinding to the same value as the ThisBinding of the calling execution context

Lo que indica claramente que esto es parte de un contexto de ejecución.

Un contexto de ejecución proporciona la información circundante que agrega significado al código que se está ejecutando. Incluye mucha más información que solo thisBinding .

El valor de esto no es "contexto". Es solo una parte del contexto de ejecución. Es esencialmente una variable local que se puede establecer mediante la llamada a cualquier objeto y, en modo estricto, a cualquier valor.

4
  • No puedo estar de acuerdo con esta respuesta. La existencia del término "contexto de ejecución" no prohíbe otros usos del "contexto" como tampoco prohíbe otros usos de "ejecución". Tal vez haya un término mejor para describir, thispero no se ofrece ninguno aquí, y podría decirse que es demasiado tarde para cerrar la puerta al "contexto". 8/06/19 a las 15:12
  • @ Roamer-1888 — gracias por la edición. Tiene razón, pero mi argumento no se basa en la existencia de un "contexto de ejecución" que excluya el de "contexto" para algún otro propósito. Más bien, se basa en que el "contexto" es inapropiado desde una perspectiva técnica y semántica. También creo que el uso de "contexto" en lugar de "esto" está desapareciendo. No veo ninguna razón para encontrar un término alternativo a this o thisBinding , simplemente se confunde y significa que en algún momento tienes que explicar que "contexto" es en realidad esto , y que de todos modos no está en "contexto". :-)
    RobG
    8 de junio de 2019 a las 23:42
  • No creo que puedas decir que esto no es de ninguna manera "contexto", cuando ya has admitido que es una parte de un contexto de ejecución, donde "ejecución" es meramente adjetivo. 9 de junio de 2019 a las 2:16
  • @ Roamer-1888 — No voy a continuar esta conversación más allá de este punto. Sí, esto es parte de un contexto de ejecución. Decir que es el contexto es como decir que un jugador de un equipo es el equipo.
    RobG
    9 de junio de 2019 a las 3:06
28

Primero, debe tener una comprensión clara scopey el comportamiento de la thispalabra clave en el contexto de scope.

this& scope:


Hay dos tipos de alcance en JavaScript. Son:

  1. Alcance global

  2. Alcance de la función

En resumen, el alcance global se refiere al objeto ventana. Las variables declaradas en un ámbito global son accesibles desde cualquier lugar.

Por otro lado, el alcance de la función reside dentro de una función. Normalmente, no se puede acceder a una variable declarada dentro de una función desde el mundo exterior.

La thispalabra clave en el ámbito global se refiere al objeto de ventana. thisdentro de una función también se refiere al objeto de ventana. Así thisque siempre nos referiremos a la ventana hasta que encontremos una forma de manipularla thispara indicar un contexto de nuestra propia elección.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   (globally "this" refers to window object)                                  -
-                                                                              -
-   function outer_function(callback){                                         -
-                                                                              -
-       // Outer function scope                                                -
-       // Inside the outer function, the "this" keyword                       -
-       //  refers to window object                                            -
-       callback() // "this" inside callback also refers to the  window object -
-   }                                                                          -
-                                                                              -
-   function callback_function(){                                              -
-                                                                              -
-       // Function to be passed as callback                                   -
-                                                                              -
-       // Here "THIS" refers to the window object also                        -
-   }                                                                          -
-                                                                              -
-   outer_function(callback_function)                                          -
-   // Invoke with callback                                                    -
-                                                                              -
--------------------------------------------------------------------------------

Diferentes formas de manipular las thisfunciones de devolución de llamada internas:

Aquí tengo una función constructora llamada Persona. Tiene una propiedad llamada namey cuatro método llamado sayNameVersion1, sayNameVersion2, sayNameVersion3, y sayNameVersion4. Los cuatro tienen una tarea específica. Acepta una devolución de llamada e invocala. La devolución de llamada tiene una tarea específica que es registrar la propiedad de nombre de una instancia de la función constructora Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // Function to be used as callback

    var parentObject = this

    console.log(parentObject)
}

Ahora creemos una instancia a partir del constructor de persona e invoquemos diferentes versiones del sayNameVersionXmétodo (X se refiere a 1, 2, 3, 4) niceCallbackpara ver de cuántas formas podemos manipular la thisdevolución de llamada interna para hacer referencia a la personinstancia.

var p1 = new Person('zami') // Create an instance of Person constructor

unir:

Lo que hace bind es crear una nueva función con la thispalabra clave establecida en el valor proporcionado.

sayNameVersion1y sayNameVersion2use bind para manipular thisla función de devolución de llamada.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

El primero se enlaza thiscon una devolución de llamada dentro del método en sí. Y para el segundo, la devolución de llamada se pasa con el objeto vinculado a ella.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

llama:

La first argumentdel callmétodo se usa como thisdentro de la función que se invoca con calladjunta.

sayNameVersion3utiliza callpara manipular el thispara referirse al objeto persona que creamos, en lugar del objeto ventana.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

Y se llama así:

p1.sayNameVersion3(niceCallback)

solicitar:

Similar a call, el primer argumento de se applyrefiere al objeto que será indicado por la thispalabra clave.

sayNameVersion4usa applypara manipular thispara referirse a un objeto persona

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

Y se llama así. Simplemente se pasa la devolución de llamada,

p1.sayNameVersion4(niceCallback)
3
  • 1
    ¡Se agradecerá cualquier crítica constructiva con respecto a la respuesta!
    AL-zami
    19 de agosto de 2017 a las 8:55
  • 1
    La palabra clave this en el ámbito global no se refiere necesariamente al objeto de ventana . Eso es cierto solo en un navegador. 23 de mayo de 2018 a las 10:04
  • 1
    @RandallFlagg escribí esta respuesta desde la perspectiva de un navegador. No dude en mejorar esta respuesta si es necesario :)
    AL-zami
    9 de julio de 2018 a las 0:14
23

No podemos vincular esto setTimeout(), ya que siempre se ejecuta con el objeto global (Ventana) . Si desea acceder al thiscontexto en la función de devolución de llamada, utilizando bind()la función de devolución de llamada, podemos lograrlo como:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
2
  • 11
    ¿En qué se diferencia esto de cualquiera de las respuestas existentes? 17/11/2017 a las 15:17
  • Re " Window": ¿No es " window" (minúsculas)? 25 de julio a las 20:46
12

La pregunta gira en torno a cómo se thiscomporta la palabra clave en JavaScript. thisse comporta de manera diferente como se muestra a continuación,

  1. El valor de thissuele estar determinado por el contexto de ejecución de una función.
  2. En el ámbito global, se thisrefiere al objeto global (el windowobjeto).
  3. Si el modo estricto está habilitado para cualquier función, entonces el valor de thisserá undefinedcomo en el modo estricto, el objeto global se refiere undefineden lugar del windowobjeto.
  4. El objeto que está delante del punto es a lo thisque se vinculará la palabra clave.
  5. Podemos establecer el valor de esta explícitamente call(), bind()yapply()
  6. Cuando newse utiliza la palabra clave (un constructor), está vinculada al nuevo objeto que se está creando.
  7. Las funciones de flecha no se vinculan this ; en cambio, thisestán vinculadas léxicamente (es decir, según el contexto original)

Como sugieren la mayoría de las respuestas, podemos usar la función de flecha o bind()Método o Auto var. Citaría un punto sobre lambdas (función de flecha) de la Guía de estilo de JavaScript de Google

Prefer using arrow functions over f.bind(this), and especially over goog.bind(f, this). Avoid writing const self = this. Arrow functions are particularly useful for callbacks, which sometimes pass unexpectedly additional arguments.

Google recomienda claramente el uso de lambdas en lugar de enlazar o const self = this

Entonces, la mejor solución sería usar lambdas como se muestra a continuación,

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

Referencias:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. funciones-de-flecha-vs-bind
2
6

Actualmente, existe otro enfoque posible si las clases se utilizan en el código.

Con el soporte de campos de clase , es posible hacerlo de la siguiente manera:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // This refers to the correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

Seguro que bajo el capó es toda la vieja función de flecha buena la que enlaza el contexto, pero de esta forma parece mucho más clara que la vinculación explícita.

Dado que se trata de una propuesta de la etapa 3, necesitará Babel y el complemento de Babel adecuado para procesarla como por ahora (08/2018).

1
  • 2
    Esta es exactamente la forma en que lo hice funcionar en Typecript: public methodName = (params) => { body }dentro de una clase. 17/02/19 a las 17:36
4

Otro enfoque, que es la forma estándar desde DOM2 de vincularse thisdentro del detector de eventos, que le permite eliminar siempre el detector (entre otros beneficios), es el handleEvent(evt)método de la EventListenerinterfaz:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

Puede encontrar información detallada sobre el uso handleEventaquí: DOM handleEvent: un estándar multiplataforma desde el año 2000

4

Yo estaba frente a un problema con Ngxla línea gráfica xAxisTickFormattingfunción que se llama desde HTML como esto: [xAxisTickFormatting]="xFormat".

No pude acceder a la variable de mi componente desde la función declarada. Esta solución me ayudó a resolver el problema para encontrar la solución correcta.

En lugar de usar la función de esta manera:

xFormat (value): string {
  return value.toString() + this.oneComponentVariable; //gives wrong result
}

Utilizar esta:

 xFormat = (value) => {
   // console.log(this);
   // now you have access to your component variables
   return value + this.oneComponentVariable
 }
3

Algunas otras personas han mencionado cómo usar el método .bind (), pero específicamente aquí es cómo puede usarlo con .then () si alguien tiene problemas para que trabajen juntos:

someFunction()
.then(function(response) {
    //'this' wasn't accessible here before but now it is
}.bind(this))

Como se mencionó en los comentarios, una alternativa sería usar una función de flecha que no tenga su propio valor 'this'

someFunction()
.then((response)=>{
    //'this' was always accessible here
})
2
  • Eso no es correcto. (1) las funciones de flecha no tienen su propio thisvalor y utilizan el valor del thisentorno que proporciona cierres. (2) por eso, .bindno afecta las funciones de las flechas. 24 de junio a las 22:58
  • buena llamada, copié el código incorrecto, actualizado para mostrar ambas variaciones 24 de junio a las 23:03
3

this en JavaScript:

El valor de thisen JavaScript está 100% determinado por cómo se llama a una función y no por cómo se define. Podemos encontrar con relativa facilidad el valor de thispor la 'regla a la izquierda del punto' :

  1. Cuando la función se crea usando la palabra clave de función, el valor de thises el objeto a la izquierda del punto de la función que se llama
  2. Si no queda ningún objeto del punto, el valor de thisdentro de una función suele ser el objeto global ( globalen Node.js y windowen un navegador). ¡No recomendaría usar la thispalabra clave aquí porque es menos explícita que usar algo como window!
  3. Existen ciertas construcciones como funciones de flecha y funciones creadas usando la Function.prototype.bind()función a que puede fijar el valor de this. Estas son excepciones de la regla, pero es realmente útil corregir el valor de this.

Ejemplo en Node.js

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

Producción:

Ingrese la descripción de la imagen aquí

Déjame guiarte a través de las salidas una por una (ignorando el primer registro a partir del segundo):

  1. thises obj2debido a la regla del punto a la izquierda, podemos ver cómo test1se llama obj2.test1();. obj2queda a la izquierda del punto y, por tanto, del thisvalor.
  2. Aunque obj2queda a la izquierda del punto, test2está vinculado a obj1través del bind()método. El thisvalor es obj1.
  3. obj2que queda del punto de la función que se llama: obj2.test3(). Por obj2lo tanto será el valor de this.
  4. En este caso: obj2.test4() obj2queda a la izquierda del punto. Sin embargo, las funciones de flecha no tienen su propio thisenlace. Por lo tanto, se vinculará al thisvalor del ámbito externo, que es el module.exportsobjeto que se registró al principio.
  5. También podemos especificar el valor de thisusando la callfunción. Aquí podemos pasar el thisvalor deseado como argumento, que es obj2en este caso.