¿Cómo acceder al correcto 'this' dentro de una devolución de llamada?

1425

Tengo una función de constructor 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 exhibe los mismos problemas.

¿Cómo puedo acceder al objeto correcto?

Felix Kling
fuente
95
De vez en cuando estoy tan harto de un cierto tipo de pregunta, que decido escribir una respuesta canónica. Aunque estas preguntas han sido respondidas como un millón de veces, no siempre es posible encontrar un buen par de preguntas + respuestas que no esté "contaminado" por información irrelevante. Este es uno de esos momentos y una de esas preguntas (y estoy aburrido). Si cree que en realidad hay una buena pregunta / respuesta canónica existente para este tipo de pregunta, avíseme y la eliminaré. ¡Sugerencias para mejorar son bienvenidas!
Felix Kling
3
Página útil de TypeScript sobre esto , aplicable principalmente a JS también.
Ondra Žižka

Respuestas:

1791

Lo que debes 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 de cómo / cuándo / dónde se definió. No se ve afectado por á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

No usar this

En realidad, no desea acceder thisen particular, pero el objeto al que hace referencia . 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 comunes son selfy that.

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

Como selfes una variable normal, obedece 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.

Conjunto 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 el que invocó .bind, solo que thisusted estableció. No importa cómo o cuándo se llame 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: Al vincular el contexto para jQuery, use jQuery.proxy [docs] en su lugar. La razón para hacer esto es para que no necesite almacenar la referencia a la función al desvincular una devolución de llamada de evento. jQuery maneja eso internamente.

ECMAScript 6: Usar funciones de flecha

ECMAScript 6 introduce funciones de flecha , que pueden considerarse funciones lambda. No tienen su propia thisatadura. En cambio, thisse busca en el alcance al igual que una variable normal. Eso significa que no tienes 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));
}

Conjunto thisde la devolución de llamada - parte 2

Algunas funciones / métodos que aceptan devoluciones de llamada también aceptan un valor al que thisdeberían 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 thisdebe referirse. 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: Si puede pasar un valor o no, thisgeneralmente se menciona en la documentación de esa función / método. Por ejemplo, el $.ajaxmétodo [docs] de jQuery describe una opción llamada context:

Este objeto se convertirá en el contexto de todas las devoluciones de llamada relacionadas con Ajax.


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 usa un método de objeto como devolución de llamada / controlador de eventos. 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 "que contiene".

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 él, 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, lo que se thisrefiere depende de cómo se llama la función , no de cómo se define .
Si el código fuera 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, úsela .bindpara unirse explícitamente thisa un valor específico

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

o llame explícitamente a la función como un "método" del objeto, utilizando una función anónima como devolución de llamada / controlador de eventos y asigne 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();
Felix Kling
fuente
39
Felix, he leído esta respuesta antes pero nunca respondí. Me preocupa que la gente use selfy thatpara referirse this. Me siento así porque thises una variable sobrecargada utilizada en diferentes contextos; mientras que selfgeneralmente corresponde a la instancia local y thatgeneralmente se refiere a otro objeto. Sé que no estableció esta regla, como la he visto aparecer en varios otros lugares, pero también es por eso que comencé a usarla _this, pero no estoy seguro de cómo se sienten los demás, excepto por la práctica no uniforme eso ha resultado.
vol7ron
3
@FelixKling, ¿sería seguro asumir que el uso de estas funciones prototipo internas siempre tendrá el comportamiento esperado independientemente de cómo se llamen (típicamente)? Cuando se usan devoluciones de llamada dentro de las funciones de prototipo, ¿hay una alternativa a bind (), self o that?
andig
55
@FelixKling Puede ser útil a veces confiar Function.prototype.call ()y Function.prototype.apply (). Particularmente con apply ()he conseguido mucho kilometraje. Estoy menos inclinado a usar bind ()tal vez solo por costumbre, aunque soy consciente (pero no estoy seguro) de que puede haber ligeras ventajas generales al usar el enlace sobre las otras opciones.
Nolo
55
Gran respuesta, pero considere agregar una solución opcional adicional que es simplemente no usar clases, nuevas o esto en absoluto.
Aluan Haddad
44
funciones de flecha re "En cambio, esto se busca en el alcance como una variable normal". totalmente hecho este clic para mí, gracias! () => this.clicked();)
alfanumérico0101
211

Aquí hay varias formas de acceder al contexto primario dentro del contexto secundario:

  1. Puedes usar la bind()función.
  2. Almacene la referencia al contexto / esto dentro de otra variable (vea el ejemplo a continuación).
  3. Utilice las funciones de flecha ES6 .
  4. Alterar el código / diseño de la función / arquitectura: para esto debe tener el comando sobre los patrones de diseño en javascript.

1. Uso 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 la 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);
  });
}
Mohan Dere
fuente
1
La opción bind () es increíble, solo pasa el puntero de este Objeto para que sea este en el otro objeto (: ¡Gracias!
Stav Bodik
El enlace () funciona a las mil maravillas. Muchas gracias +1 de mi parte :)
Anjana Silva
56

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

object.property();

Cuando obtiene la propiedad del objeto y la 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 obtienes 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á utilizando jQuery, debe utilizar el $.proxymétodo, ya bindque no es compatible con todos los navegadores:

this.saveNextLevelData($.proxy(this.setAll, this));
Guffa
fuente
33

El problema con el "contexto"

El término "contexto" se utiliza a veces para referirse al objeto referenciado por este . Su uso es inapropiado porque no encaja semántica o técnicamente con ECMAScript's this .

"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 es todos los parámetros, alcance y esto dentro del alcance de algún código de ejecución.

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

Establezca ThisBinding en el mismo valor que ThisBinding del contexto de ejecución de llamada

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 .

Entonces el valor de esto no es "contexto", es solo una parte de un contexto de ejecución. Es esencialmente una variable local que puede establecerse mediante la llamada a cualquier objeto y, en modo estricto, a cualquier valor.

RobG
fuente
No puedo estar de acuerdo con esta respuesta. La existencia del término "contexto de ejecución" no proscribe otros usos del "contexto" más de lo que prohíbe otros usos de la "ejecución". Quizás haya un mejor término para describir, thispero aquí no se ofrece ninguno, y podría decirse que es demasiado tarde para cerrar la puerta al "contexto".
Roamer-1888
@ Roamer-1888: gracias por la edición. Tienes razón, pero mi argumento no se basa en la existencia del "contexto de ejecución" que excluye el "contexto" para algún otro propósito. Más bien, se basa en que el "contexto" es inapropiado tanto desde una perspectiva técnica como 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 para esto o este enlace , solo se ofusca 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
No creo que puedas decir que esto no es de ninguna manera "contexto", cuando ya ha admitido que es una parte de un contexto de ejecución, donde "ejecución" es simplemente adjetivo.
Roamer-1888
@ 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
RobG, lástima que no quieras continuar. Es un debate interesante. Gracias por darme tu tiempo.
Roamer-1888
31

Debe saber sobre "esta" palabra clave.

Según mi punto de vista, puede implementar "esto" de tres maneras (Self / Función de flecha / Método de enlace)

Una función de esta palabra clave se comporta de manera un poco diferente en JavaScript en comparación con otros idiomas.

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 una función.

No se puede establecer mediante 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, independientemente de cómo se llame,

y ES2015 introdujo funciones de flecha que no proporcionan su propia vinculación (conserva el valor de este 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 de uso frecuente en los controladores de eventos (especialmente en cierres).

Referencia : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

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 pueden usarse como constructores.

Referencia : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

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

Método 3 : : el método bind () crea una nueva función que,

cuando se le llama, tiene esta palabra clave establecida en el valor proporcionado,

con una secuencia dada de argumentos que preceden a cualquier proporcionado cuando se llama a la nueva función.

Referencia: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

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

Primero, debe tener una comprensión scopey un comportamiento claros de las thispalabras clave en el contexto de scope.

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

en resumen, el alcance global se refiere al objeto de ventana. Las variables declaradas en un alcance 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 la variable declarada dentro de una función desde el mundo exterior. thisLa palabra clave en el ámbito global se refiere al objeto de ventana. thisla función interna también se refiere al objeto de la ventana, por thislo que siempre se referirá a la ventana hasta que encontremos una forma de manipular 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 outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

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

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

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 del constructor de personas e invoquemos diferentes versiones del sayNameVersionXmétodo (X se refiere a 1,2,3,4) niceCallbackpara ver cuántas formas podemos manipular la thisdevolución de llamada interna para referirnos a la personinstancia.

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

enlace:

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 vincula thiscon la devolución de llamada dentro del propio método. Y para el segundo, la devolución de llamada se pasa con el objeto vinculado a él.

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

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

llamada :

El first argumentdel callmétodo se utiliza como thisdentro de la función que se invoca concall unido a él.

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

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

y se llama así:

p1.sayNameVersion3(niceCallback)

aplicar :

Similar a call, el primer argumento de se applyrefiere al objeto que será indicado porthis palabra clave.

sayNameVersion4utiliza applypara manipular thispara referirse al objeto persona

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

y se llama de la siguiente manera. Simplemente se pasa la devolución de llamada,

p1.sayNameVersion4(niceCallback)
AL-zami
fuente
1
¡Cualquier crítica constructiva con respecto a la respuesta será apreciada!
AL-zami
1
La palabra clave this en el ámbito global no necesariamente se refiere al objeto de ventana . Eso es cierto solo en un navegador.
Randall Flagg
1
@RandallFlagg escribí esta respuesta desde la perspectiva de un navegador. No dude en inhalar esta respuesta si es necesario :)
AL-zami
19

No podemos vincular esto a 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 lograr lo siguiente:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
Datta Chanewad
fuente
99
¿Cómo es esto diferente de cualquiera de las respuestas existentes?
Felix Kling
13

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

  1. El valor de this generalmente está determinado por un contexto de ejecución de funciones.
  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 delwindow objeto.
  4. El objeto que está parado antes del punto es a lo que estará vinculada esta palabra clave.
  5. Podemos establecer el valor de esto explícitamente con call(),bind() yapply()
  6. Cuando el new se usa palabra clave (un constructor), está vinculada al nuevo objeto que se está creando.
  7. Las funciones de flecha no se unen this ; en cambio, thisse vincula léxicamente (es decir, según el contexto original)

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

Prefiere usar las funciones de flecha sobre f.bind (this), y especialmente sobre goog.bind (f, this). Evite escribir const self = this. Las funciones de flecha son particularmente útiles para devoluciones de llamada, que a veces pasan argumentos adicionales inesperados.

Google recomienda claramente usar 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. flecha-funciones-vs-enlace
Code_Mode
fuente
Esta pregunta es específicamente sobre el uso de funciones / métodos como devoluciones de llamada. Su respuesta podría ser mejor para stackoverflow.com/q/3127429/218196 .
Felix Kling
@FelixKling La pregunta Sí es sobre el uso de funciones / métodos como devoluciones de llamada en ese problema principal debido al manejo de la thispalabra clave, por eso dividí mi respuesta en dos partes, una sobre thisy la segunda sobre el uso de funciones / métodos como devoluciones de llamada. Siéntase libre de editar la respuesta.
Code_Mode
Encuentro su cuarto punto redactado de manera ambigua. Considere el ejemplo "Problema al usar métodos con este objeto como devoluciones de llamada" , donde el objeto correcto está parado antes del punto, pero aún así el contexto no es ese objeto.
bleistift2
7

Actualmente hay otro enfoque posible si se usan clases en el código.

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

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

Seguramente, bajo el capó, todo es una buena función de flecha buena que vincula el contexto, pero de esta forma se ve mucho más claro que el enlace explícito.

Dado que es la Propuesta de la Etapa 3, necesitará babel y el complemento de babel apropiado para procesarlo por ahora (08/2018).

Skyboyer
fuente
2
Esta es exactamente la forma en que lo hice funcionar en Typecript: public methodName = (params) => { body }dentro de una clase.
yeyeyerman
5

Otro enfoque, que es la forma estándar desde que DOM2 se une thisdentro del detector de eventos, que le permite eliminar siempre el receptor (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í: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38

Andrea Puddu
fuente
0

this en JS:

El valor de thisen JS está 100% determinado por cómo se llama una función y no por cómo se define. Podemos relativamente fácil encontrar el valor de thisla 'izquierda de la regla de puntos' :

  1. Cuando se crean funciones utilizando la palabra clave de función, el valor de this es el objeto a la izquierda del punto de la función que se llama
  2. Si no queda ningún objeto del punto, entonces el valor thisdentro de una función es a menudo el objeto global ( globalen el nodo, windowen el navegador). No recomendaría usar la thispalabra clave aquí porque es menos explícita que usar algo comowindow !
  3. Existen ciertas construcciones como las funciones de flecha y las funciones creadas usando la Function.prototype.bind()función que puede fijar el valor de this. Estas son excepciones de la regla, pero son realmente útiles para fijar el valor de this.

Ejemplo en nodeJS

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

Salida:

ingrese la descripción de la imagen aquí

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

  1. thises obj2por la izquierda de la regla de puntos, podemos ver cómo test1se llama obj2.test1();. obj2queda del punto y por lo tanto elthis valor.
  2. A pesar de obj2que queda del punto, test2está obligado a obj1través del bind()método. Entonces el thisvalor es obj1.
  3. obj2que queda del punto de la función que se llama: obj2.test3(). Por obj2lo tanto será el valor dethis .
  4. En este caso: obj2.test4() obj2queda del punto. Sin embargo, la función de flecha no tiene su propio thisenlace. Por lo tanto, se unirá al thisvalor del ámbito externo, que es el module.exportsobjeto que se registró al principio.
  5. También podemos especificar el valor de thismediante el uso de la callfunción. Aquí podemos pasar el thisvalor deseado como argumento, que es obj2en este caso.
Willem van der Veen
fuente