【问题标题】:What is better way to access this. Function.bind vs capturing variables有什么更好的方法来访问它。 Function.bind 与捕获变量
【发布时间】:2020-07-19 11:40:20
【问题描述】:

这是一个基本问题,但这提出了一个有趣的问题。 例如,

var Foobar = function(){
    this.baz = 100;    
    this.timer = null;

    this.printLazy = function(){
         
        this.timer = setTimeout(function(){
              console.log(this.baz); //correctly bind this.
        }.bind(this), 1000);
         
    }

}

创建一个传统类,我们可以创建实例并调用printLazy as

var myBar = new Foobar();
myBar.printLazy();

现在在上面的代码中,printLazy 方法设置了一个计时器,我们在其中访问了this

同样的事情可以使用捕获来实现,

   this.printLazy = function(){
       var self = this; //capture this.
         
        this.timer = setTimeout(function(){
              console.log(self.baz); //correctly bind this.
        }, 1000);
         
    }
  1. 这些方法中的一种是否比另一种更好? (考虑效率或性能)
  2. 第二个方法是否会导致内存泄漏,如果它被调用让我们说 1000 次或更多次快速连续,其中 self 将被函数内的其他部分引用?

【问题讨论】:

  • 使用箭头函数 ``` var Foobar =()=>{ let baz = 100;让计时器=空; this.printLazy = ()=>{ setTimeout(()=>{ console.log(baz); //正确绑定 this. }, 1000); } }```
  • 是的。箭头函数为此使用了正确的范围。但我期望的是一个更理论的解释,涉及 es5 风格的答案,涉及捕获与绑定。

标签: javascript variables scope


【解决方案1】:

这些方法中的一种是否比另一种更好? (考虑效率或性能)

不是真的。在您的特定示例中,使用bind 的版本创建了一个不必要的函数对象(但JavaScript 引擎在这方面非常很快)。但这也意味着您传递的函数 setTimeout 不会关闭任何东西,这是 JavaScript 引擎可以用来优化附加到它的上下文的信息(“闭包优化”)。

但在现代环境中,您可能会在这种情况下使用箭头函数而不是 self 选项:

this.printLazy = function(){
     
    this.timer = setTimeout(() => {
          console.log(this.baz);
    }, 1000);
     
}

这将在计时器触发时记录this.baz。根据您需要记录的内容,另一个选项是setTimeout(console.log, 1000, this.baz)。不同之处在于,此版本将记录 this.baz 在计时器设置时的值,而不是在它触发时记录的值。 (它还依赖于 console.log,在大多数 [但也许不是全部] 环境中,当你调用它时并不关心 this 是什么。)那是因为 setTimeout 传递了你给它的任何额外参数调用它时调用的函数。

第二种方法是否会导致内存泄漏,如果它被调用让我们快速连续说 1000 次或更多次,其中 self 将被函数内的其他部分引用?

没有。内存泄漏不是由快速执行操作引起的。它们是由于当您不再需要它而不释放它时持有内存而引起的。你正在做的事情不会那样做。

【讨论】:

  • 感谢您的回答,如果不支持 es 箭头功能(IE),您是否建议使用捕获比 Function.bind 更好地访问它?在 babel repl 中也是 babel 将箭头转换为 es5 的方式。
  • @XPD - 箭头函数关闭 this 就像一个变量,是的。这并不意味着我说在没有箭头功能的过时环境中,甚至在具有箭头功能的现代环境中,使用第二个示例比使用第一个示例“更好”。我已经更新了答案以更清楚地说明这一点。 bind 仍有一席之地。
【解决方案2】:

最近遇到了同样的问题(在 React 中),发现 this article 显示了几个选项。以下是您的情况的 3 个,最后一个是推荐选项。

选项 1
使用箭头函数。但是,这仍然会在每次调用 printLazy 时创建一个新函数。

this.printLazy = function(){
    this.timer = setTimeout(() => {
        console.log(this.baz); //correctly bind this.
    }, 1000);
}

选项 2
创建第二个函数并在构造函数中绑定它,这仍然存在性能缺陷。

var Foobar = function(){
    constructor() {
        this.printLazyCallback = this.printLazyCallback.bind(this)
    }

    printLazyCallback() {
         console.log(this.baz); //correctly bind this.
    }
}

选项 3(您应该使用的那个)
创建第二个函数作为类道具箭头函数

var Foobar = function(){
    printLazyCallback = () => {
         console.log(this.baz); //correctly bind this.
    }
}

【讨论】:

  • 基本上你是正确的并且被赞成,不幸的是我期待一个 es5 风格的答案。
  • 不确定这是否有效,但您可以尝试在它之外执行此操作:Foobar.printLazyCallback = Foobar.printLazyCallback.bind(Foobar)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多