简体   繁体   English

回调和这个

[英]Callbacks and this

I have a directory with files that I need to parse and save in an array of JavaScript objects. 我有一个目录,其中包含我需要解析并保存在JavaScript对象数组中的文件。 In the constructor, as soon as I reach point 2 in the code below, this becomes undefined and in point 3 I don't have access to this.data . 在构造函数中,一旦到达以下代码中的点2this将变为undefined并且在点3中,我无权访问this.data What's the best way to fix the code and achieve the goal? 修复代码并实现目标的最佳方法是什么?

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
};

I tried saving this as self , but in the end self ends up with proper array, while this does not: 我想保存thisself ,但最终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
  };

The this object changes anytime you change from a function's scope to another. 每当您从一个函数的作用域更改为另一个作用域时, this对象都会更改。

You can solve this by saving the this object you want to a variable (in my example: self ): 您可以通过将所需的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

See documentation on Mozilla for this . 请参阅有关Mozilla的文档this

To see an example, please refer to this fiddle . 要查看示例,请参阅此小提琴

As an alternative to Vsevolod's answer, you can also use bind . 作为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));
}

Bind is slower than using a closure, but that only really matters in very tight loops where you're doing a ton of iterations and is unlikely to be an issue in most scenarios. 绑定比使用闭包要慢,但这只在非常紧密的循环中才有意义,在循环中您要进行大量迭代,并且在大多数情况下都不太可能成为问题。

this refers to the 'current' context. this是指“当前”上下文。

In you example you can just save the 'outer' this to a local variable 在您例如,您可以在“外”只保存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);
    });
}

PS while using bind is not prohibited either, the solution with assigning this to a local variable looks more elegant and will ensure that you will not forget to add another bind to the callback PS在使用bind也不会被禁止,以分配解决this一个局部变量看起来更优雅,将确保你不会忘记另一个添加bind回调

I'm not sure why this is the case, but if you do this.data = this.data or self = this in your prototype it outputs the correct value. 我不确定为什么会这样,但是如果在原型中执行this.data = this.dataself = this ,它将输出正确的值。 Otherwise it returns the whole Service instance at the time it was created. 否则,它将在创建时返回整个Service实例。 Here is a snippet you can try with a dummy Service and getData example. 这是一个片段,您可以尝试使用虚拟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()); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM