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?
source to share
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.
- 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
- 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
source to share