绑定函数而不是闭包来注入额外的参数

时间:2014-09-11 03:59:47

标签: javascript

似乎不是

{  onClick: function(event){  someHandler('clicked', event); }  }

你可以写

{  onClick: someHandler.bind(null, 'clicked'); }

看起来更简洁,感觉更有功能"。

这有什么缺点吗?没有创建闭包是否有性能提升?有没有办法保持关闭会收到的this

2 个答案:

答案 0 :(得分:1)

这不是一个“封闭”,它只是一个匿名函数。

我个人更喜欢bind版本,因为正如你所说,它更简洁。然而,根据这个jsperf(http://jsperf.com/anonymous-function-vs-bind),它慢了十倍,这让我感到非常惊讶,特别是因为这里使用的bind似乎是原生的。一个假设是bind,或者更确切地说它生成的函数,需要围绕查看传入的参数并构造一个参数列表以传递给被调用的函数。

要维护this,您需要bind的变体,例如Underscore的_.partial,或者您可以自己编写一个:

function partial(fn) {
    var slice = Array.prototype.slice,
        args = slice.call(arguments, 1);
    return function() {
        return fn.apply(this, args.concat(slice.call(arguments, 1)));
    };
}

不幸的是,使用partial{ onClick: partial(someHandler, 'clicked'); })的变体仍然比匿名函数慢十倍。

jsperf中的另一个测试用例支持参数列表处理导致减速的假设,jsperf定义了一个partial1,它只预定义了底层函数的两个参数中的第一个:

function partial1(fn, a) {
    return function(b) {
        return fn.call(this, a, b);
    };
}

使用那个不必创建和合并参数列表的那个,只会导致25-35%的减速,而不是90%。

如果我们不关心通过this,这可以让我们避免使用Function#call

function partial2(fn, a) {
    return function(b) {
        return fn(a, b);
    };
}

然后放缓只有10%。

但是,如果我们真的想通过this,那么我们需要将匿名函数版本编写为

{ onClick: function(event) { someHandler.call(this, 'clicked', event); }  }

这也导致原始版本减速20-25%,可能是由于调用Function#call的成本。所以从这个意义上来说,asusming你想要通过this,匿名函数的性能和我们自己开发的partial1(基于参数数量而定制)的表现大致相同等价,这并不奇怪,因为他们基本上做同样的工作。

答案 1 :(得分:1)

  
      
  1. 这有什么缺点吗?是不是有性能提升   创造了一个封闭?
  2.   

是的,bind有性能缺陷,您可以找到更多详细信息here

  
      
  1. 有没有办法保持关闭会收到的这个?
  2.   

这取决于您定义this

的方式

如果您在示例

中传递my_klass之类的对象,则效果很好
function some(a,b){
   console.log("a is: " + a);
   console.log("b is: " + b);
   console.log("this.val: " + this.val)
}

function klass(val){
   this.val = val;
}

my_klass = new klass("test val");

var ab = {
  click: function(a){ some('clicked',a);},
  bclick: some.bind(my_klass,'clicked')
}

ab.bclick("param");

输出

a is: clicked
b is: param
this.val: test val

如果您喜欢

不会工作
function some(a,b){
   console.log("a is: " + a);
   console.log("b is: " + b);
   console.log("this.val: " + this.val)
}

var ab = {
  val: 99,
  click: function(a){ some('clicked',a);},
  bclick: some.bind(this,'clicked')
}

ab.bclick("param"); // Expected to print 99

输出

a is: clicked
b is: param
this.val: undefined