Bound function instead of closure to enter additional arguments

It seems that instead of

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

      

You can write

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

      

which looks more concise and feels more "functional".

Are there any disadvantages? Is there a performance gain by not creating a closure? Is there a way to save this

that would get a close?

+3


source to share


2 answers


This is not a "closure", it is just an anonymous function.

Personally, I prefer the version bind

because, as you say, it is more concise. However, according to this jsperf ( http://jsperf.com/anonymous-function-vs-bind ) it is ten times slower, which surprises me a lot, especially since bind

being native is used here . One hypothesis is that bind

, or rather, the function it generates should work on looking at the arguments passed and creating a list of arguments that are passed to the called function.

To support this

you need a variant bind

like Underscore _.partial

, or you can write it yourself:

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

      

Unfortunately, changing using partial

( { onClick: partial(someHandler, 'clicked'); }

) is still ten times slower than the anonymous function.

The hypothesis that processing an argument list causes a slowdown is supported by another test case in jsperf that defines partial1

which only predetermines the first of exactly two arguments to the main function:

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

      



Using one that shouldn't create and concatenate argument lists results in a slowdown of only 25-35% instead of 90%.

If we don't need to go through this

, which avoids using Function#call

:

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

      

Then the deceleration is only 10%.

However, if we really want to go through this

, then we need to write the anonymous version of the function as

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

      

which also results in a 20-25% slowdown from the original version, presumably due to the cost of the call Function#call

. So in that sense, the asusming you want to go through this

, the performance of the anonymous function and our homebrew partial1

set up for the number of arguments is roughly equivalent, which isn't surprising since they're essentially doing identical work.

+1


source


  • Are there any disadvantages? Is there a performance gain rather than creating a closure?

Yes, binding has a performance disadvantage, you can find more details here

  1. Is there a way to keep this closure?

It depends on how you define this

This works well if you are passing an object like my_klass

in the example

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");

      



Output:

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

      

He wont work if you like

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

      

Output:

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

      

+1


source







All Articles