[英]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
. 在构造函数中,一旦到达以下代码中的点2 ,
this
将变为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: 我想保存
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
};
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.data
或self = 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. 这是一个片段,您可以尝试使用虚拟
Service
和getData
示例。
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.