Невозможно использовать «this» внутри функции с анонимной функцией - PullRequest
0 голосов
/ 11 октября 2018

Совершенно новый для 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();
});

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Область действия в 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 
};

Пожалуйста, обратитесь к ответу Атишая Джайна в этой же ветке, чтобы узнать другой способ сделать это.

0 голосов
/ 11 октября 2018

Код обновлен.Используйте это

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);
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...