当“ this”丢失上下文链接时该怎么办

哈Ha! 我向您介绍Cristi Salcescu撰写的文章“当这种“失去语境”时该怎么办”译文

避免丢失上下文的最佳方法是不使用this 。 但是,这并不总是可能的。 例如,我们与使用代码的其他人的代码或库一起工作。

原型系统中的对象文字,构造函数,类对象构造函数。 在原型系统中使用此伪参数以便访问对象的属性。

让我们看一些情况。

嵌套函数


会丢失嵌套函数内部的上下文引用。

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

doSomething()方法具有两个嵌套函数: doAnotherthing()log() 。 当调用service.doSomething()时会丢失嵌套函数中的上下文引用。

绑定()


解决问题的一种方法是使用bind()方法。 看下面的代码:

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

bind()创建函数的新版本,该函数在调用时已经具有this的某个值。

函数doAnotherThing(){/*...*/}.bind(this)创建doAnotherThing()函数的版本,该函数从doSomething()中获取此值。

那/自我


另一个选择是声明并使用新的that / self变量,该变量将存储doSomething()方法中的this值。

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

我们必须在嵌套函数中使用this的所有方法中声明let that = this

箭头功能


箭头功能为我们提供了解决此问题的另一种方法。

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

箭头函数不会为此创建自己的上下文,而是使用周围上下文的this值。 在上面的示例中,它使用父函数的this的值。

该方法的缺点是我们无法指定箭头函数的名称。 函数的名称起着重要的作用,因为它增加了代码的可读性并描述了其目的。

下面是相同的代码,但函数以变量名表示:

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

回调函数(方法作为回调)


将方法用作回调函数时, 会丢失上下文引用。 让我们看下面的类:

 class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);//undefined } } let service = new 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); function run(fn){ fn(); } 

在上述所有情况下, 这都会丢失上下文链接。

绑定()


我们可以使用bind()解决此问题。 以下是此选项的代码:

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

箭头功能


另一种方法是创建一个调用service.doSomething()的箭头函数。

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

反应组件


在组件中,当方法用作事件的回调时, 会丢失上下文引用。

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

作为解决方案,我们可以在将使用bind(this)的构造函数中创建新函数。

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

不要使用“ this”


不, -没有上下文丢失的问题。 可以使用工厂函数创建对象。 看一下这个例子:

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

如果将该方法用作回调,则上下文仍然保留。

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

结论


在各种情况下都会丢失上下文引用。
bind() ,使用那个/自变量和箭头函数是解决上下文问题的方法。

使用工厂函数可以创建不使用this的对象。

Source: https://habr.com/ru/post/zh-CN421959/


All Articles