使用Function.prototype.bind或保存的引用

时间:2013-10-25 11:12:34

标签: javascript

这是主观的(基于意见的) - 但只是在一定程度上,不要急于投票结束。在工作中引起一些争论,因为每个人都有不同的意见,人们正试图强制执行一种方式。

简单上下文:当您可以选择将闭包中的引用保存到实例或使用polyfilled Function.prototype.bind时,您会看到哪种方法存在哪些不利之处?

为了说明可能的用例,我只是编写了一些类方法。

模式一,保存参考:

obj.prototype.addEvents = function(){
    var self = this;

    // reference can be local also - for unbinding. 
    this.onElementClick = function(){
        self.emit('clicked');
        self.element.off('click', self.onElementClick);
    };

    this.element.on('click', this.onElementClick);
};

模式二,一个简单的fn.bind:

obj.prototype.addEvents = function(){
    // saved reference needs to be bound to this to be unbound
    // once again, this can be a local var also.  
    this.onElementClick = function(){
        this.emit('clicked');
        this.element.off('click', this.onElementClick);
    }.bind(this);

    this.element.on('click', this.onElementClick);
};

模式两个半,proto方法到事件:

obj.prototype.addEvents = function(){
    // delegate event to a class method elsewhere 
    this.element.on('click', this.onElementClick.bind(this));
};

obj.prototype.onElementClick = function(){
    this.emit('clicked');
    this.element.off('click', this.onElementClick); // not matching due to memoized bound 
};

就我个人而言,我认为没有一种正确的方法可以做到这一点,并应根据具体情况进行判断。我很喜欢保存的参考模式。我被告知了。

问题回顾:

是否有任何GC问题需要考虑/注意?

对于这两种方法,您是否还有其他明显的缺点或陷阱?

Polyfill效果或事件原生.bind与已保存的参考?

2 个答案:

答案 0 :(得分:1)

我个人的偏好是使用保存的参考方法。由于JavaScript处理this的方式,有时候this的价值推理会非常困难。

绑定很好但是如果你错过.bind(this)它看起来像一个bug。

后者暴露太多;每次需要回调时,您都需要在API中公开另一个帮助程序。


有许多方法可以使用原型设计。我认为最重要的是选择一个并坚持下去。

答案 1 :(得分:1)

  

是否有任何GC问题需要考虑/注意?

较旧的引擎不会从闭包中推断出仍然使用了哪些变量,并且会保留整个范围。使用bind确实很容易,因为显式传递了上下文,未收集的范围不包含其他变量。

但是,如果你正在使用函数表达式(如模式#1和#2),这没有任何区别。

  

对于这两种方法,您是否还有其他明显的缺点或陷阱?

保存参考:

  • 需要额外的行来声明变量,有时甚至需要一个全新的范围(IEFE)
  • 由于您需要重命名变量
  • ,因此无法轻松移动代码

使用bind:

  • 在函数表达式的末尾容易被忽略(就像调用IEFE一样),从上到下阅读时this引用的内容并不清楚
  • 轻易忘记

我个人倾向于使用bind,因为它简洁,但只能在其他地方声明的函数(方法)。

  

Polyfill性能或事件本机.bind与已保存的参考?

你不在乎。


在您的示例中,您实际上不需要对绑定函数和off方法的引用。 jQuery可以自己解决这个问题,你可以使用one method绑定fire-once监听器。然后您的代码可以缩短为

obj.prototype.addEvents = function(){
    this.element.one('click', this.emit.bind(this, 'clicked'));
};