Como acessar o `this` correto dentro de um retorno de chamada?

1425

Eu tenho uma função construtora que registra um manipulador 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);

No entanto, não consigo acessar a datapropriedade do objeto criado dentro do retorno de chamada. Parece que thisnão se refere ao objeto que foi criado, mas a outro.

Eu também tentei usar um método de objeto em vez de uma função anônima:

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

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

mas exibe os mesmos problemas.

Como posso acessar o objeto correto?

Felix Kling
fonte
95
De vez em quando fico tão farta de um certo tipo de pergunta que decido escrever uma resposta canônica. Mesmo que essas perguntas tenham sido respondidas um milhão de vezes, nem sempre é possível encontrar um bom par de perguntas + respostas que não seja "poluído" por informações irrelevantes. Este é um daqueles momentos e uma dessas perguntas (e eu estou entediado). Se você acha que há realmente uma boa pergunta / resposta canônica para esse tipo de pergunta, entre em contato e eu excluirei esta. Sugestões para melhorias são bem-vindas!
Felix Kling #
3
Página TypeScript útil sobre isso , aplicável principalmente a JS também.
Ondra Žižka

Respostas:

1791

O que você deve saber sobre this

this(também conhecido como "o contexto") é uma palavra-chave especial dentro de cada função e seu valor depende apenas de como a função foi chamada, não de como / quando / onde foi definida. Não é afetado por escopos lexicais como outras variáveis ​​(exceto para funções de seta, veja abaixo). aqui estão alguns exemplos:

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 saber mais this, consulte a documentação do MDN .


Como se referir ao correto this

Não use this

Você realmente não deseja acessar thisem particular, mas o objeto a que se refere . É por isso que uma solução fácil é simplesmente criar uma nova variável que também se refere a esse objeto. A variável pode ter qualquer nome, mas os comuns são selfe that.

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

Como selfé uma variável normal, ela obedece às regras de escopo lexical e é acessível dentro do retorno de chamada. Isso também tem a vantagem de poder acessar o thisvalor do retorno de chamada.

Conjunto explicitamente thisdo retorno de chamada - parte 1

Pode parecer que você não tem controle sobre o valor de thisporque seu valor é definido automaticamente, mas esse não é realmente o caso.

Toda função possui o método .bind [docs] , que retorna uma nova função thisvinculada a um valor. A função tem exatamente o mesmo comportamento que você chamou .bind, apenas que thisfoi definido por você. Não importa como ou quando essa função é chamada, thissempre se refere ao valor passado.

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

Nesse caso, estamos vinculando os retornos de chamada thisao valor de MyConstructor's this.

Nota: Ao vincular o contexto para jQuery, use jQuery.proxy [docs] . O motivo para fazer isso é que você não precisa armazenar a referência à função ao desvincular um retorno de chamada de evento. O jQuery lida com isso internamente.

ECMAScript 6: Usar funções de seta

O ECMAScript 6 apresenta funções de seta , que podem ser consideradas funções lambda. Eles não têm sua própria thisligação. Em vez disso, thisé pesquisado no escopo como uma variável normal. Isso significa que você não precisa ligar .bind. Esse não é o único comportamento especial que eles têm; consulte a documentação do MDN para obter mais informações.

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

Conjunto thisdo retorno de chamada - parte 2

Algumas funções / métodos que aceitam retornos de chamada também aceitam um valor ao qual os retornos de chamada thisdevem se referir. Isso é basicamente o mesmo que vincular você mesmo, mas a função / método faz isso por você. Array#map [docs] é esse método. Sua assinatura é:

array.map(callback[, thisArg])

O primeiro argumento é o retorno de chamada e o segundo argumento é o valor ao qual thisdeve se referir. Aqui está um exemplo 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: Se você pode ou não passar um valor thisgeralmente é mencionado na documentação dessa função / método. Por exemplo, o $.ajaxmétodo do jQuery [docs] descreve uma opção chamada context:

Este objeto será transformado no contexto de todos os retornos de chamada relacionados ao Ajax.


Problema comum: Usando métodos de objeto como retornos de chamada / manipuladores de eventos

Outra manifestação comum desse problema é quando um método de objeto é usado como manipulador de retorno de chamada / evento. Funções são cidadãos de primeira classe em JavaScript e o termo "método" é apenas um termo coloquial para uma função que é um valor de uma propriedade de objeto. Mas essa função não tem um link específico para seu objeto "contendo".

Considere o seguinte exemplo:

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

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

A função this.methodé atribuída como manipulador de eventos de clique, mas se document.bodyfor clicado, o valor registrado será undefined, porque dentro do manipulador de eventos thisse refere à document.bodyinstância, e não à instância Foo.
Como já mencionado no início, o que thisse refere depende de como a função é chamada , não de como é definida .
Se o código fosse o seguinte, pode ser mais óbvio que a função não tenha uma referência implícita ao objeto:

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


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

Foo.prototype.method = method;

A solução é a mesma mencionada acima: Se disponível, use .bindpara ligar explicitamente thisa um valor específico

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

ou chame explicitamente a função como um "método" do objeto, usando uma função anônima como retorno de chamada / manipulador de eventos e atribua o objeto ( this) a outra variável:

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

ou use uma função de seta:

document.body.onclick = () => this.method();
Felix Kling
fonte
39
Felix, eu já li essa resposta antes, mas nunca respondi. Fico preocupado com o fato de as pessoas usarem selfe thatpara se referirem this. Eu me sinto assim porque thisé uma variável sobrecarregada usada em diferentes contextos; enquanto que selfgeralmente corresponde à instância local e thatgeralmente se refere a outro objeto. Sei que você não definiu essa regra, pois já a vi aparecer em vários outros lugares, mas também é por isso que comecei a usá-la _this, mas não tenho certeza de como os outros se sentem, exceto pela prática não uniforme. isso resultou.
vol7ron
3
@FelixKling seria seguro supor que o uso dessas funções internas do protótipo sempre terá o comportamento esperado, independentemente de como elas são (normalmente) chamadas? Ao usar retornos de chamada dentro de funções de protótipo, existe uma alternativa para bind (), self ou isso?
andig
5
@FelixKling Às vezes, pode ser útil confiar em Function.prototype.call ()e Function.prototype.apply (). Particularmente, apply ()eu tenho muita quilometragem. Estou menos inclinado a usar bind ()talvez apenas por hábito, embora esteja ciente (mas não certo) de que possa haver pequenas vantagens gerais em usar o bind sobre as outras opções.
Nolo
5
Ótima resposta, mas considere adicionar uma solução opcional adicional, que é apenas para não usar classes, novas ou isso.
Aluan Haddad 12/02
4
re arrow functions "Em vez disso, isso é pesquisado no escopo como uma variável normal." totalmente fez esse clique para mim, obrigado! () => this.clicked();)
alfanumérico0101
211

Aqui estão várias maneiras de acessar o contexto pai dentro do contexto filho -

  1. Você pode usar a bind()função
  2. Armazene a referência ao contexto / isto dentro de outra variável (veja o exemplo abaixo).
  3. Use as funções de seta do ES6 .
  4. Altere o código / função design / arquitetura - para isso, você deve ter o comando sobre os padrões de design em javascript.

1. Use a bind()função

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

Se você estiver usando underscore.js- http://underscorejs.org/#bind

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

2 Armazene a referência ao contexto / isto dentro de outra variável

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

Função de 3 setas

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
Mohan Dere
fonte
1
A opção bind () é incrível é apenas passar o ponteiro do objeto a ser o presente do outro objeto (:! Graças
Stav Bodik
O bind () funciona como um encanto. Muito obrigado +1 de mim :)
Anjana Silva
56

Está tudo na sintaxe "mágica" de chamar um método:

object.property();

Quando você obtém a propriedade do objeto e a chama de uma só vez, o objeto será o contexto do método. Se você chamar o mesmo método, mas em etapas separadas, o contexto será o escopo global (janela):

var f = object.property;
f();

Quando você obtém a referência de um método, ele não está mais anexado ao objeto, é apenas uma referência a uma função simples. O mesmo acontece quando você obtém a referência para usar como retorno de chamada:

this.saveNextLevelData(this.setAll);

É aí que você vincula o contexto à função:

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

Se você estiver usando jQuery, deverá usar o $.proxymétodo, pois bindnão é suportado em todos os navegadores:

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

O problema com o "contexto"

O termo "contexto" às vezes é usado para se referir ao objeto referenciado por isso . Seu uso é inadequado, porque não se encaixa tanto semanticamente ou tecnicamente com ECMAScript do presente .

"Contexto" significa as circunstâncias que envolvem algo que adiciona significado, ou algumas informações anteriores e posteriores que dão significado extra. O termo "contexto" é usado no ECMAScript para se referir ao contexto de execução , que é todos os parâmetros, escopo e isso dentro do escopo de algum código em execução.

Isso é mostrado na seção 10.4.2 do ECMA-262 :

Defina ThisBinding com o mesmo valor que ThisBinding do contexto de execução da chamada

o que indica claramente que isso faz parte de um contexto de execução.

Um contexto de execução fornece as informações circundantes que adicionam significado ao código que está sendo executado. Inclui muito mais informações do que apenas thisBinding .

Portanto, o valor disso não é "contexto", é apenas uma parte de um contexto de execução. É essencialmente uma variável local que pode ser definida pela chamada para qualquer objeto e, no modo estrito, para qualquer valor.

RobG
fonte
Não posso concordar com esta resposta. A existência do termo "contexto de execução" não proíbe outros usos de "contexto", assim como não é permitido outros usos de "execução". Talvez haja um termo melhor para descrever, thismas nenhum é oferecido aqui, e é provavelmente muito tarde para fechar a porta no "contexto".
Roamer-1888
@ Roamer-1888 - obrigado pela edição. Você está certo, mas meu argumento não se baseia na existência de "contexto de execução" que exclui o de "contexto" para algum outro propósito. Pelo contrário, baseia-se no "contexto" ser inapropriado da perspectiva técnica e semântica. Eu também acho que o uso de "contexto" em vez de "isso" está acabando. Não vejo motivo para encontrar um termo alternativo para this ou thisBinding , apenas ofusca e significa que, em algum momento, você precisa explicar que "contexto" é realmente esse e que não está em "contexto". :-)
RobG
Eu não acho que você possa dizer que isso não é de forma alguma "contexto", quando você já admitiu que é uma parte de um contexto de execução, em que "execução" é meramente adjetiva.
Roamer-1888
@ Roamer-1888 - Não vou continuar essa conversa além deste ponto. Sim, isso faz parte de um contexto de execução. Dizer que é o contexto é como dizer que um jogador de uma equipe é a equipe.
RobG 9/06/19
RobG, pena que você não queira continuar. É um debate interessante. Obrigado por me dar seu tempo.
Roamer-1888
31

Você deve saber sobre "esta" palavra-chave.

De acordo com minha opinião, você pode implementar "isso" de três maneiras (função Self / Arrow / Bind Method)

A palavra-chave de uma função se comporta de maneira um pouco diferente no JavaScript em comparação com outros idiomas.

Também possui algumas diferenças entre o modo estrito e o modo não estrito.

Na maioria dos casos, o valor disso é determinado pela maneira como uma função é chamada.

Ele não pode ser definido por atribuição durante a execução e pode ser diferente cada vez que a função é chamada.

O ES5 introduziu o método bind () para definir o valor de uma função, independentemente de como é chamada,

e o ES2015 introduziram funções de seta que não fornecem essa ligação por si só (mantém o valor this do contexto lexical anexo).

Método 1: Auto-Self está sendo usado para manter uma referência ao original, mesmo quando o contexto está mudando. É uma técnica frequentemente usada em manipuladores de eventos (especialmente em fechamentos).

Referência : 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 : Função de seta - Uma expressão de função de seta é uma alternativa sintaticamente compacta a uma expressão de função regular,

embora sem suas próprias ligações às palavras-chave this, argumentos, super ou new.target.

As expressões de função de seta são inadequadas como métodos e não podem ser usadas como construtores.

Referência : 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);
    });
}

Method3 : Bind- O método bind () cria uma nova função que,

quando chamado, tem sua palavra-chave definida com o valor fornecido,

com uma determinada sequência de argumentos que precede qualquer fornecida quando a nova função é chamada.

Referência: 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
fonte
25

Primeiro, você precisa ter uma compreensão clara scopee o comportamento da thispalavra-chave no contexto de scope.

this& scope:


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

   1) Global Scope

   2) Function Scope

em resumo, o escopo global refere-se ao objeto da janela. Variáveis ​​declaradas em um escopo global são acessíveis de qualquer lugar. Por outro lado, o escopo da função reside dentro de uma função. a variável declarada dentro de uma função não pode ser acessada normalmente fora do mundo. thisA palavra-chave no escopo global refere-se ao objeto de janela. thisfunção interna também se refere ao objeto de janela. Portanto this, sempre se referirá à janela até encontrarmos uma maneira de manipular thispara indicar um contexto de nossa própria escolha.

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

Maneiras diferentes de manipular thisfunções internas de retorno de chamada:

Aqui eu tenho uma função construtora chamada Person. Ele tem uma propriedade chamada namee quatro método chamado sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Todos os quatro têm uma tarefa específica. Aceite um retorno de chamada e invoque-o. O retorno de chamada possui uma tarefa específica que é registrar a propriedade name de uma instância da função do construtor 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)

}

Agora vamos criar uma instância a partir do construtor de pessoas e chamar diferentes versões do sayNameVersionXmétodo (X refere-se a 1,2,3,4) niceCallbackpara ver quantas maneiras podemos manipular o thisretorno de chamada interno para se referir à personinstância.

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

ligar :

O que o bind faz é criar uma nova função com a thispalavra - chave configurada para o valor fornecido.

sayNameVersion1e sayNameVersion2use bind para manipular thisa função de retorno de chamada.

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

primeiro, ligue-se thisao retorno de chamada dentro do próprio método. E, para o segundo, um retorno de chamada é passado com o objeto vinculado a ele.

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

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

ligar :

A first argumentdo callmétodo é usado como thisdentro da função que é chamado com calla ela ligada.

sayNameVersion3usa callpara manipular o thispara se referir ao objeto de pessoa que criamos, em vez do objeto de janela.

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

e é chamado da seguinte maneira:

p1.sayNameVersion3(niceCallback)

Aplique :

Semelhante ao call, o primeiro argumento de applyrefere-se ao objeto que será indicado pela thispalavra-chave.

sayNameVersion4usa applypara manipular thispara se referir ao objeto de pessoa

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

e é chamado da seguinte maneira. Simplesmente o retorno de chamada é passado,

p1.sayNameVersion4(niceCallback)
AL-zami
fonte
1
qualquer crítica construtiva sobre a resposta será apreciada!
AL-zami
1
A palavra-chave this no escopo global não se refere necessariamente ao objeto window . Isso é verdade apenas em um navegador.
Randall Flagg
1
@RandallFlagg i escreveu esta resposta a partir de um navegador perspective.Fell livre para inhance esta resposta, se necessário :)
AL-Zami
19

Não podemos vincular isso setTimeout(), como ele sempre executa com o objeto global (Window) , se você deseja acessar o thiscontexto na função de retorno de chamada, usando bind()a função de retorno de chamada que podemos obter como:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
Datta Chanewad
fonte
9
Como isso é diferente de qualquer uma das respostas existentes?
precisa
13

A questão gira em torno de como a thispalavra-chave se comporta em javascript. thisse comporta de maneira diferente como abaixo,

  1. O valor de thisgeralmente é determinado por um contexto de execução de funções.
  2. No escopo global, thisrefere-se ao objeto global (o windowobjeto).
  3. Se o modo estrito estiver ativado para qualquer função, o valor de thisserá undefinedcomo no modo estrito, objeto global se refere ao undefinedlugar do windowobjeto.
  4. O objeto que está diante do ponto é o que a palavra-chave this será vinculada.
  5. Podemos definir o valor desta explicitamente call(), bind()eapply()
  6. Quando a newpalavra-chave é usada (um construtor), isso é vinculado ao novo objeto que está sendo criado.
  7. As funções de seta não são vinculadas this - em vez disso, thissão vinculadas lexicamente (ou seja, com base no contexto original)

Como a maioria das respostas sugere, podemos usar a função Seta ou bind()Método ou Var. Eu citaria um ponto sobre lambdas (função de seta) do Google JavaScript Style Guide

Prefira usar as funções de seta em vez de f.bind (this), e especialmente em goog.bind (f, this). Evite escrever const self = this. As funções de seta são particularmente úteis para retornos de chamada, que às vezes passam argumentos adicionais inesperados.

O Google recomenda claramente usar lambdas em vez de vincular ou const self = this

Portanto, a melhor solução seria usar lambdas como abaixo,

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

Referências:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. arrow-funções-vs-bind
Code_Mode
fonte
Esta pergunta é especificamente sobre o uso de funções / métodos como retornos de chamada. Sua resposta pode ser mais adequada para stackoverflow.com/q/3127429/218196 .
Felix Kling
@FelixKling Sim, a pergunta é sobre o uso de funções / métodos como retornos de chamada na questão principal, devido ao manuseio de thispalavras-chave; é por isso que dividi minha resposta em duas partes, uma sobre a thissegunda sobre o uso de funções / métodos como retornos de chamada. Sinta-se livre para editar a resposta.
Code_Mode 19/02/19
Acho seu quarto ponto redigido ambiguamente. Considere o exemplo "Problema ao usar métodos com este objeto como retornos de chamada" , em que o objeto correto está diante do ponto, mas ainda assim o contexto não é esse objeto.
bleistift2 22/02
7

Atualmente, existe outra abordagem possível se as classes forem usadas no código.

Com o suporte de campos de classe , é possível fazer o seguinte:

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

Certamente, sob o capô, todas as funções de seta boa e antiga vinculam o contexto, mas, dessa forma, parece muito mais claro que a ligação explícita.

Como é uma proposta do estágio 3, você precisará do babel e do plug - in babel apropriado para processá-lo como agora (08/2018).

skyboyer
fonte
2
Foi exatamente dessa maneira que consegui trabalhar no Typescript: public methodName = (params) => { body }dentro de uma classe.
Yeyeyerman
5

Outra abordagem, que é a maneira padrão desde a ligação do DOM2this no ouvinte de eventos, que permite remover sempre o ouvinte (entre outros benefícios), é o handleEvent(evt)método da EventListenerinterface:

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

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

Informações detalhadas sobre o uso handleEventpodem ser encontradas aqui: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38

Andrea Puddu
fonte
0

this em JS:

O valor de thisem JS é 100% determinado pela forma como uma função é chamada, e não como é definida. Nós podemos relativamente fácil encontrar o valor de thispelo 'esquerda da regra dot' :

  1. Quando a função é criada usando a palavra-chave function, o valor de thisé o objeto deixado no ponto da função que é chamado
  2. Se não houver nenhum objeto deixado no ponto, o valor de thisdentro de uma função geralmente será o objeto global ( globalno nó, windowno navegador). Eu não recomendaria usar a thispalavra - chave aqui porque é menos explícita do que usar algo como window!
  3. Existem certas construções, como funções de seta e funções criadas usando a Function.prototype.bind()função que pode fixar o valor de this. Essas são exceções à regra, mas são realmente úteis para corrigir o valor de this.

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

Resultado:

insira a descrição da imagem aqui

Deixe-me guiá-lo pelas saídas 1 por 1 (ignorando o primeiro log a partir do segundo):

  1. thisé obj2por causa da esquerda da regra dos pontos, podemos ver como test1é chamado obj2.test1();. obj2é deixado do ponto e, portanto, o thisvalor.
  2. Mesmo que obj2está à esquerda do ponto, test2é obrigado a obj1via do bind()método. Então o thisvalor é obj1.
  3. obj2está à esquerda do ponto da função que é chamado: obj2.test3(). Portanto obj2, será o valor de this.
  4. Nesse caso: obj2.test4() obj2fica à esquerda do ponto. No entanto, a função de seta não tem sua própria thisligação. Portanto, ele será vinculado ao thisvalor do escopo externo, que é o module.exportsobjeto que foi registrado no início.
  5. Também podemos especificar o valor de thisusando a callfunção Aqui podemos passar o thisvalor desejado como argumento, que é obj2neste caso.
Willem van der Veen
fonte