面试题答案
一键面试修改后的代码如下:
class MyLibrary {
constructor() {
this.data = [];
this.fetchData = function() {
const self = this;
setTimeout(function() {
// 假设这里通过AJAX获取数据并更新self.data
// 实际代码中会使用如fetch等方式
self.data.push('new data');
console.log(self.data);
}, 1000);
}
}
}
const library = new MyLibrary();
library.fetchData();
修改前后this
指向的变化
- 修改前:使用箭头函数时,箭头函数本身没有自己的
this
,它会捕获其所在上下文的this
值,在fetchData
方法中,箭头函数捕获的this
就是MyLibrary
实例的this
,所以可以直接访问和更新this.data
。 - 修改后:使用普通函数时,普通函数有自己独立的
this
。在setTimeout
回调中,this
指向的是全局对象(在浏览器环境中是window
),而不是MyLibrary
实例。为了能正确访问和更新MyLibrary
实例的data
属性,通过const self = this
将MyLibrary
实例的this
保存到self
变量中,在普通函数回调中使用self
来访问和更新data
属性。
在复杂类库调用嵌套场景下确保this
指向正确的方法
- 使用
bind
方法:在定义函数时,使用bind
方法将函数的this
绑定到特定对象。例如:
class MyLibrary {
constructor() {
this.data = [];
this.fetchData = function() {
setTimeout(function() {
this.data.push('new data');
console.log(this.data);
}.bind(this), 1000);
}
}
}
这里bind(this)
将setTimeout
回调函数的this
绑定到MyLibrary
实例。
- 使用ES6类的方法:在ES6类中,方法内部的
this
默认指向类的实例。可以将复杂操作封装成类的方法,确保this
指向正确。例如:
class MyLibrary {
constructor() {
this.data = [];
this.fetchData = function() {
setTimeout(this.updateData.bind(this), 1000);
}
}
updateData() {
this.data.push('new data');
console.log(this.data);
}
}
这样在updateData
方法中,this
始终指向MyLibrary
实例。
- 使用
self
或that
变量:与上述修改后的代码类似,在外部作用域保存this
,在内部回调函数中使用保存的变量。这种方法简单直观,适用于各种嵌套场景。