无法在具有匿名功能的函数内使用“this”
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了无法在具有匿名功能的函数内使用“this”相关的知识,希望对你有一定的参考价值。
对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();
});
答案
如果有嵌套函数,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在同一个帖子中的答案,了解另一种方法。
另一答案
代码已更新。用这个
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);
};
以上是关于无法在具有匿名功能的函数内使用“this”的主要内容,如果未能解决你的问题,请参考以下文章