开发者问题收集

类内的 Javascript 递归

2017-07-17
14007

我试图让递归方法在类上下文中工作。在我的类中,我有以下方法:

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

但是,当我使用此方法(以前我将其用作 function countChildren = ... 时,该方法有效)时,它无法...在递归中找到 (?) 本身: 无法读取未定义的属性“countChildren”

有人有什么想法吗?

3个回答

出现此问题的原因是,在循环中, this 被重新定义为内部函数范围。

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;
}
krillgar
2017-07-17

尝试在构造函数中绑定方法。
此外,通过对 forEach 使用箭头函数,您可以保留类的 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;
    }
}
Sumi Straessle
2017-07-17

变量 this 在以下范围内重新定义:

  1. for 循环的内部范围
  2. 内联函数声明中
  3. 异步函数调用中。

我同意 krillgar 关于声明 self 的说法。 它解决了我的异步调用问题。

obj.prototype.foo = function (string){
   var self = this;
   if(string){ do something }
   else
   setTimeout(function(){
     self.foo("string");
     }, 5000);
}
CDM
2018-06-10