node.js尚不成熟,在理解某些概念时遇到问题。
在以下代码中,第console.log('Item ' + this.itemNo + ' is done.');
行显示为未定义。
在this.itemNo
内部无法访问setTimeout
的可能原因是什么?
async = require("async");
function doSomethingOnceAllAreDone(){
console.log("Everything is done.");
}
function Item(itemNo, delay){
this.delay = delay;
this.itemNo = itemNo;
console.log(`Created item ${itemNo} with ${delay} seconds`)
}
Item.prototype.someAsyncCall = function(callback){
setTimeout(function(){
console.log('Item ' + this.itemNo + ' is done.');
if(typeof callback === "function") callback();
}, this.delay);
};
// Create some items
let items = [];
for (let i = 0; i < 20; i++) {
items.push(new Item(i, Math.random() * 3000));
}
// Loop though items and create tasks
var asyncTasks = [];
items.forEach(function(item){
asyncTasks.push(function(callback){
item.someAsyncCall(function(){
callback();
});
});
});
// Add an extra task
asyncTasks.push(function(callback){
setTimeout(function(){
console.log("Additional item is done.");
callback();
}, 3000);
});
// Execute the tasks in parallel and notify once done
async.parallel(asyncTasks, function(){
doSomethingOnceAllAreDone();
});
答案 0 :(得分:2)
如果有嵌套函数,则Javascript的作用域非常重要。
(请注意以下代码中的注释)
Item.prototype.someAsyncCall = function(callback) { // <-- Item object/class is accessible in lexical *this*
var itemNo = this.itemNo; // Accessible
setTimeout(function() { // <-- Here, we have a closure with its own scope and ITS OWN lexical *this*
var itemNoDuplicate = this.itemNo; // Not accessible as we are inside `setTimeout` scope
if(typeof callback === "function") callback();
}, this.delay);
};
有两种解决方法可以解决您的问题:
通过箭头功能使用ES6模式:
Item.prototype.someAsyncCall = function(callback) {
// Arrow function in ES6 preserves lexical *this* of the closest parent
setTimeout(() => {
if(typeof callback === "function") callback();
}, this.delay);
};
充分利用
bind
(如果您想坚持使用ES5)
Item.prototype.someAsyncCall = function(callback) {
setTimeout(function() {
var itemNo = this.itemNo; // Yeaah! Its accessible
if(typeof callback === "function") callback();
}.bind(this), this.delay);
// ^^^^^^^^^^^ -- We have bind the closest parents scope to this closure, // and now its accessible inside it
};
请在同一主题中参考Atishay Jain的答案,以了解另一种方法。
答案 1 :(得分:0)
代码已更新。使用这个
Item.prototype.someAsyncCall = function(callback){
var _this = this;
setTimeout(function(){
console.log('Item ' + _this.itemNo + ' is done.');
if(typeof callback === "function") callback();
}, this.delay);
};
或使用此
Item.prototype.someAsyncCall = function(callback){
setTimeout(() => {
console.log('Item ' + this.itemNo + ' is done.');
if(typeof callback === "function") callback();
}, this.delay);
};