Qu茅 hacer cuando "esto" pierde el enlace de contexto

Hola Habr! Les presento la traducci贸n del art铆culo "Qu茅 hacer cuando" esto "pierde contexto" por Cristi Salcescu .

La mejor manera de evitar perder este contexto es no usarlo. Sin embargo, esto no siempre es posible. Por ejemplo, trabajamos con el c贸digo o la biblioteca de otra persona que usa esto .

Literal de objeto, funci贸n de constructor, constructor de objeto de clase en el sistema prototipo. Este pseudopar谩metro se utiliza en el sistema de creaci贸n de prototipos para dar acceso a las propiedades del objeto.

Veamos algunos casos.

Funciones anidadas


esto pierde la referencia de contexto dentro de las funciones anidadas.

class Service { constructor(){ this.numbers = [1,2,3]; this.token = "token"; } doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ //Cannot read property 'forEach' of undefined console.log(number); console.log(this.token); }); }, 100); } } let service = new Service(); service.doSomething(); 

El m茅todo doSomething () tiene dos funciones anidadas: doAnotherthing () y log () . Al llamar a service.doSomething () , esto pierde la referencia de contexto en la funci贸n anidada.

bind ()


Una forma de resolver el problema es con el m茅todo bind () . Echa un vistazo al siguiente 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 () crea una nueva versi贸n de la funci贸n, que cuando se llama ya tiene un cierto valor de esto .

La funci贸n doAnotherThing () {/*...*/}.bind(this) crea una versi贸n de la funci贸n doAnotherThing () , que toma el valor de esto de doSomething () .

eso / yo


Otra opci贸n es declarar y usar la nueva variable that / self , que almacenar谩 este valor del m茅todo doSomething () .

 doSomething(){ let that = this; setTimeout(function doAnotherThing(){ that.numbers.forEach(function log(number){ console.log(number); console.log(that.token); }); }, 100); } 

Debemos declarar let that = this en todos los m茅todos que usan esto en funciones anidadas.

Funciones de flecha


La funci贸n de flecha nos da otra forma de resolver este problema.

 doSomething(){ setTimeout(() => { this.numbers.forEach(number => { console.log(number); console.log(this.token); }); }, 100); } 

Las funciones de flecha no crean su propio contexto para esto , sino que usan el valor this del contexto circundante. En el ejemplo anterior, usa el valor de esto de la funci贸n padre.

La desventaja de este m茅todo es que no podemos especificar el nombre de la funci贸n de flecha. El nombre de la funci贸n juega un papel importante, ya que aumenta la legibilidad del c贸digo y describe su prop贸sito.

A continuaci贸n se muestra el mismo c贸digo con una funci贸n expresada en t茅rminos de un nombre de variable:

 doSomething(){ let log = number => { console.log(number); console.log(this.token); } let doAnotherThing = () => { this.numbers.forEach(log); } setTimeout(doAnotherThing, 100); } 

Funciones de devoluci贸n de llamada (M茅todo como devoluci贸n de llamada)


esto pierde referencia de contexto cuando se usa el m茅todo como una funci贸n de devoluci贸n de llamada. Veamos la siguiente clase:

 class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);//undefined } } let service = new Service(); 

Veamos situaciones en las que el m茅todo service.doSomething () se usa como una funci贸n de devoluci贸n de llamada.

 //callback on DOM event $("#btn").click(service.doSomething); //callback for timer setTimeout(service.doSomething, 0); //callback for custom function run(service.doSomething); function run(fn){ fn(); } 

En todos los casos anteriores, esto pierde el enlace de contexto.

bind ()


Podemos usar bind () para resolver este problema. A continuaci贸n se muestra el c贸digo para esta opci贸n:

 //callback on DOM event $("#btn").click(service.doSomething.bind(service)); //callback for timer setTimeout(service.doSomething.bind(service), 0); //callback for custom function run(service.doSomething.bind(service)); 

Funci贸n de flecha


Otra forma es crear una funci贸n de flecha que llame a service.doSomething () .

 //callback on DOM event $("#btn").click(() => service.doSomething()); //callback for timer setTimeout(() => service.doSomething(), 0); //callback for custom function run(() => service.doSomething()); 

Reaccionar componentes


En los componentes, esto pierde referencia de contexto cuando los m茅todos se usan como devoluciones de llamada para eventos.

 class TodoAddForm extends React.Component { constructor(){ super(); this.todos = []; } componentWillMount() { this.setState({desc: ""}); } add(){ let todo = {desc: this.state.desc}; //Cannot read property 'state' of undefined this.todos.push(todo); } handleChange(event) { //Cannot read property 'setState' of undefined this.setState({desc: event.target.value}); } render() { return <form> <input onChange={this.handleChange} value={this.state.desc} type="text"/> <button onClick={this.add} type="button">Save</button> </form>; } } ReactDOM.render( <TodoAddForm />, document.getElementById('root')); 

Como soluci贸n, podemos crear nuevas funciones en el constructor que usar谩n bind (this) .

 constructor(){ super(); this.todos = []; this.handleChange = this.handleChange.bind(this); this.add = this.add.bind(this); } 

No use "esto"


No esto , no hay problemas con la p茅rdida de contexto. Los objetos se pueden crear utilizando funciones de f谩brica . Echa un vistazo a este ejemplo:

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

El contexto permanece si usa el m茅todo como devoluci贸n de llamada.

 let service = Service(); service.doSomething(); //callback on DOM event $("#btn").click(service.doSomething); //callback for timer setTimeout(service.doSomething, 0); //callback for custom function run(service.doSomething); 

Conclusi贸n


esto pierde referencia de contexto en varias situaciones.
bind () , usando esa variable / self y las funciones de flecha son formas de resolver problemas de contexto.

Las funciones de f谩brica permiten crear objetos sin usar esto .

Source: https://habr.com/ru/post/es421959/


All Articles