【问题标题】:Javascript recursion within a class类中的 Javascript 递归
【发布时间】:2017-07-17 15:06:40
【问题描述】:

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

    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 = ...),它无法...找到 (?) 本身:递归时的Cannot read property 'countChildren' of undefined

有人有什么想法吗?

【问题讨论】:

  • 这是因为forEach 的回调有它自己的范围,并将this 的值设置为类以外的值。

标签: javascript class recursion


【解决方案1】:

问题出现是因为在您的循环中,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。
  • 我不喜欢 that = this 把戏。有一些结构是这个特定用例的语言的一部分,主要是 .bind() 和 ES6 中的箭头函数。
  • @SumiStraessle 我根本不是this 的粉丝。 OP 似乎比 Javascript 更新,所以我不想混淆它们。我看到你的回答是这样的,所以我不会附加到我的答案中。
  • 不用担心。我喜欢用箭头函数来解决作用域地狱问题,它也使代码更具可读性。
  • @SumiStraessle 我没有花太多时间在他们身上,因为我的上一个项目是服务器端的。下次我做客户端工作时,我会看看将它们与 TypeScript 一起使用,因为不幸的是,我的企业工作通常仍然需要以 IE 为目标。
【解决方案2】:

尝试在构造函数中绑定方法。
此外,通过为您的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;
    }
}

【讨论】:

  • 这可能有效,但我发现@krillgar 的回答是最直接的。感谢您的回复。
  • 查看我对that = this 技巧的评论。由于您使用类,因此您使用的是 ES6 语法,这意味着您可以访问箭头函数,这些函数不会重新绑定 this 的范围。也试试。你的代码会感谢你的。
  • 嗯...好的,那我再看看
  • 如果你想要some documentation
  • 我试过了,这也有效。我同意它看起来更好。
【解决方案3】:

变量this 重新定义在:

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

我同意 krillgar 的自我声明。 它解决了我的异步调用问题。

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

【讨论】:

    【解决方案4】:

    foreach 中的 this 比类中的 this 多。在您的情况下,这指的是当前正在迭代的元素。

    你需要绑定作用域。

    n.children.forEach(function (n) {
       this.countChildren(n, levelWidth, level+1);
    }.bind(this));   
    

    【讨论】:

      【解决方案5】:

      尝试使用.call() 调用该函数。这样您就可以直接指定上下文。

      像这样:

      this.countChildren.call(this, n, levelWid);th, level+1

      编辑: 注意到我的错误,你真正应该做的是绑定匿名函数:

      像这样:

        n.children.forEach(function (n) {
          this.countChildren(n, levelWidth, level+1);
        }.bind(this)); 
      

      【讨论】:

        猜你喜欢
        • 2015-05-01
        • 2012-09-29
        • 1970-01-01
        • 2022-11-27
        • 2022-01-07
        • 2017-05-08
        • 2020-01-05
        • 2014-08-23
        • 2011-06-07
        相关资源
        最近更新 更多