Olá Habr! Apresento a você a tradução do artigo
"O que fazer quando" isso "perde o contexto" por
Cristi Salcescu .
A melhor maneira de evitar a perda
desse contexto é não usá-
lo . No entanto, isso nem sempre é possível. Por exemplo, trabalhamos com o código ou a biblioteca de outra pessoa que usa
isso .
Objeto literal, função construtora, construtor de objeto de classe no sistema de protótipo. Este pseudo-
parâmetro é usado no sistema de prototipagem para dar acesso às propriedades do objeto.
Vejamos alguns casos.
Funções aninhadas
isso perde a referência de contexto dentro de funções aninhadas.
class Service { constructor(){ this.numbers = [1,2,3]; this.token = "token"; } doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){
O método
doSomething () possui duas funções aninhadas:
doAnotherthing () e
log () . Ao chamar
service.doSomething () ,
isso perde a referência de contexto na função aninhada.
bind ()
Uma maneira de resolver o problema é com o método
bind () . Dê uma olhada no seguinte código:
doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ console.log(number); console.log(this.token); }.bind(this)); }.bind(this), 100); }
bind () cria uma nova versão da função, que quando chamada já tem um certo valor
disso .
A função doAnotherThing () {/*...//..bind(this) cria uma versão da função
doAnotherThing () , que retira o valor
disso de
doSomething () .
isso / eu
Outra opção é declarar e usar a nova variável
that / self , que armazenará
esse valor no método
doSomething () .
doSomething(){ let that = this; setTimeout(function doAnotherThing(){ that.numbers.forEach(function log(number){ console.log(number); console.log(that.token); }); }, 100); }
Devemos declarar
let that = this em todos os métodos usando
isso em funções aninhadas.
Funções de seta
A função de seta nos fornece outra maneira de resolver esse problema.
doSomething(){ setTimeout(() => { this.numbers.forEach(number => { console.log(number); console.log(this.token); }); }, 100); }
As funções de seta não criam seu próprio contexto para
isso , mas usam o valor
this do contexto circundante. No exemplo acima, ele usa o valor
disso da função pai.
A desvantagem desse método é que não podemos especificar o nome da função de seta. O nome da função desempenha um papel importante, pois aumenta a legibilidade do código e descreve sua finalidade.
Abaixo está o mesmo código com uma função expressa em termos de um nome de variável:
doSomething(){ let log = number => { console.log(number); console.log(this.token); } let doAnotherThing = () => { this.numbers.forEach(log); } setTimeout(doAnotherThing, 100); }
Funções de retorno de chamada (método como retorno de chamada)
isso perde a referência de contexto ao usar o método como uma função de retorno de chamada. Vejamos a seguinte classe:
class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);
Vejamos situações em que o método
service.doSomething () é usado como uma função de retorno de chamada.
Em todos os casos acima,
isso perde o link de contexto.
bind ()
Podemos usar o
bind () para resolver esse problema. Abaixo está o código para esta opção:
Função de seta
Outra maneira é criar uma função de seta que chama
service.doSomething () .
Reagir componentes
Nos componentes,
isso perde a referência de contexto quando os métodos são usados como retornos de chamada para eventos.
class TodoAddForm extends React.Component { constructor(){ super(); this.todos = []; } componentWillMount() { this.setState({desc: ""}); } add(){ let todo = {desc: this.state.desc};
Como solução, podemos criar novas funções no construtor que usarão
bind (this) .
constructor(){ super(); this.todos = []; this.handleChange = this.handleChange.bind(this); this.add = this.add.bind(this); }
Não use "isto"
Sem
isso - sem problemas com a perda de contexto. Objetos podem ser criados usando
funções de fábrica . Veja este exemplo:
function Service() { let numbers = [1,2,3]; let token = "token"; function doSomething(){ setTimeout(function doAnotherThing(){ numbers.forEach(function log(number){ console.log(number); console.log(token); }); }, 100); } return Object.freeze({ doSomething }); }
O contexto permanece se você usar o método como retorno de chamada.
let service = Service(); service.doSomething();
Conclusão
isso perde a referência de contexto em várias situações.
bind () , usar
essa variável
/ self e as funções de seta são formas de resolver problemas de contexto.
As funções de fábrica tornam possível criar objetos sem usar
isso .