回调和这个

时间:2014-12-22 20:10:19

标签: javascript node.js

我有一个包含文件的目录,我需要解析并保存在JavaScript对象数组中。在构造函数中,只要我在下面的代码中达到第2点this就会变成undefined而在第3点我没有访问this.data。修复代码并实现目标的最佳方法是什么?

function Service(path) {
    this.data = [];
    console.log(this); // point 1
    fs.readdir(path, function (err, files) {
        console.log(this); // point 2
        files.forEach(function (file) {
            fs.readFile(path + file, function (err, data) {
                parseString(data, function (err, result) {
                    this.data.push(result); // point 3
                });
            });
        }, this);
    });
}

Service.prototype.getData = function () {
   // do something with `this.data` and return the result
};

我尝试将this保存为self,但最后self以正确的数组结束,而this则没有:

  function Service(path) {
    var self = this;
    this.data = [];
    fs.readdir(path, function (err, files) {
        files.forEach(function (file) {
            fs.readFile(path + file, function (err, data) {
                parseString(data, function (err, result) {
                    self.data.push(result);
                });
            });
        });
    });
    setTimeout(function () {
        console.log(this); \\ point x
        console.log(self); \\ point y
    }, 3000);    
  }

  Service.prototype.getData = function () {
    // do something with `this.data` and return the result
  };

4 个答案:

答案 0 :(得分:3)

this对象在您从函数的范围更改为另一个范围时随时更改。

您可以通过将所需的this对象保存到变量(在我的示例中为self)来解决此问题:

function Service(path) {
    var self = this;
    self.data = [];
    console.log(this); // point 1
    fs.readdir(path, function (err, files) {
        console.log(self); // point 2
        files.forEach(function (file) {
            fs.readFile(path + file, function (err, data) {
                parseString(data, function (err, result) {
                    self.data.push(result); // point 3
                });
            });
        });
    });
}

Service.prototype.getData = function () {
    var self = this;

    setTimeout(function () {
        console.log(self.data);
    }, 100);
};

var serv = new Service();
serv.getData(); // your array

请参阅documentation on Mozilla for this

要查看示例,请参阅this fiddle

答案 1 :(得分:3)

作为Vsevolod答案的替代方案,您还可以使用bind

function Service(path) {
    this.data = [];
    console.log(this); // point 1
    fs.readdir(path, function (err, files) {
        console.log(this); // point 2
        files.forEach(function (file) {
            fs.readFile(path + file, function (err, data) {
                parseString(data, function (err, result) {
                    this.data.push(result); // point 3
                }.bind(this));
            });
        }, this);
    }.bind(this));
}

绑定比使用闭包更慢,但这只会在非常紧凑的循环中非常重要,您需要进行大量的迭代,并且在大多数情况下不太可能成为问题。

答案 2 :(得分:1)

this指的是当前的'上下文。

在你的例子中,你可以保存'外部' this到本地变量

function Service(path) {
    var $this = this;
    this.data = [];
    console.log(this); // point 1
    fs.readdir(path, function (err, files) {
        console.log($this); // point 2
        files.forEach(function (file) {
            fs.readFile(path + file, function (err, data) {
                parseString(data, function (err, result) {
                    $this.data.push(result); // point 3
                });
            });
        }, $this);
    });
}

使用bind时PS也不被禁止,将this分配给局部变量的解决方案看起来更优雅,并确保您不会忘记将另一个bind添加到回调

答案 3 :(得分:1)

我不确定为什么会出现这种情况,但如果您在原型中执行this.data = this.dataself = this,则会输出正确的值。否则,它在创建时返回整个Service实例。以下是您可以尝试使用虚拟ServicegetData示例的代码段。



function Service(array) {
  var self = this;
  this.data = [];
  console.log(this); // point 1
  array.forEach(function(item) {
    self.data.push(item); // point 2
  });
}

Service.prototype.getData = function() {
  self = this;
  return self.data;
};

var serv = new Service(['bob', 'aerith']);

console.log(serv.getData());