可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to get a recursion method to work in a class context. Within my class I have the following method:
countChildren(n, levelWidth, level) {
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) {
levelWidth.push(0);
}
levelWidth[level + 1] += n.children.length;
n.children.forEach(function (n) {
this.countChildren(n, levelWidth, level+1);
});
}
// Return largest openend width
return levelWidth;
}
However, when I use this method (which worked before when I just used it as function countChildren = ...
) it can't... find (?) itself: Cannot read property 'countChildren' of undefined
at the recursion.
Does anyone have any ideas?
回答1:
The problem arises because within your loop, this
gets redefined to the inner function scope.
countChildren(n, levelWidth, level) {
var self = this; // Get a reference to your object.
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) {
levelWidth.push(0);
}
levelWidth[level + 1] += n.children.length;
n.children.forEach(function (n) {
// Use "self" instead of "this" to avoid the change in scope.
self.countChildren(n, levelWidth, level+1);
});
}
// Return largest openend width
return levelWidth;
}
回答2:
Try binding the method in the constructor.
Also, by using an arrow function for your forEach
, you keep the scope of the class' this
.
export class MyClass {
constructor(){
this.countChildren = this.countChildren.bind(this);
}
countChildren(n, levelWidth, level){ ... }
countChildren(n, levelWidth, level) {
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) {
levelWidth.push(0);
}
levelWidth[level + 1] += n.children.length;
n.children.forEach( n => { // arrow function do not need to rebind this
this.countChildren(n, levelWidth, level+1);
});
}
// Return largest openend width
return levelWidth;
}
}
回答3:
The this inside the foreach than the this in the class. In your case, this refers to the current element being iterated.
you need to bind the scope.
n.children.forEach(function (n) {
this.countChildren(n, levelWidth, level+1);
}.bind(this));
回答4:
the variable this
Gets redefined within:
- the inner scope of a for loop
- within a inline function declariation
- within asynchronous function calls.
I agree with krillgar with the declaration of self.
it fixed my problem with an asynchronous call.
obj.prototype.foo = function (string){
var self = this;
if(string){ do something }
else
setTimeout(function(){
self.foo("string");
}, 5000);
}
回答5:
Try using .call()
to invoke the function. That way you can specify the context directly.
Like this:
this.countChildren.call(this, n, levelWid);
th, level+1
Edit:
Noticed my error, what you should really do is bind the anonymous function:
like this:
n.children.forEach(function (n) {
this.countChildren(n, levelWidth, level+1);
}.bind(this));