I'm reading a book about writing JavaScript frameworks and found this code snippet. But I don't understand how it works, especially the bind.bind
usage? Does anyone have a clue?
var bind = Function.prototype.bind;
var apply = bind.bind(bind.apply);
var fn = apply([].concat);
var a = [1, 2, 3], b = [4, [5, 6], 7];
fn(a, b);
//output [1, 2, 3, 4, 5, 6, 7]
This takes me back to the days of solving and expanding equations.
1 . First, lets expand the first apply function:
var bind = Function.prototype.bind;
var apply = bind.bind(bind.apply);
var fn = apply([].concat);
Transforms to:
var apply = Function.prototype.bind.bind(Function.prototype.bind.apply);
var fn = apply([].concat)
2 . Secondly, we expand the fn function:
var fn = Function.prototype.bind.bind(Function.prototype.bind.apply)([].concat);
3 . We now invent a js algebra rule and replace the bind.bind...()
invocation with the call invocation.
Actually we implement a replacement base on the notion that:
someFunction.bind(arg1)(arg2) <==> someFunction.call(arg1, arg2)
Therefore we can replace that and get:
var fn = Function.prototype.bind.call(Function.prototype.bind.apply, [].concat);
4 . For our second js algebra rule we devise that:
someFn.bind.call(target, ...) <==> target.bind(...)
.
someFn
is not important here because we don't call bind() on it. We invoke call
on the bind
- replacing the this
that was someFn
and therefor it is replaced with target
.
Therefore we replace the bind.call(target)
with the target.bind alternative
var fn = Function.prototype.bind.apply.bind([].concat)
5 . If the last permutation was also doing invocation () we could have done a replace like:
fn([1, 2], [3, 4]) <==> [].concat.apply([1, 2], [3, 4])
But we have only the bind without the invocation which we can replace and is equivalent to:
var fn = function (arg1, arg2) {
return [].concat.apply(arg1, arg2);
}
// instead arg1 and arg2 we could use more accurate arguments logic also.
Final Result
var fn = Function.prototype.bind.apply.bind([].concat)
// or
var fn = function (arg1, arg2) {
return [].concat.apply(arg1, arg2);
}
The fn
function takes the concat
function and lets us us it in a functional style, without calling it from an object. Instead of concat
binded to this
of the caller, fn
applies it on arg1
as this
and arg2
as the other params to concatenation to arg1
.
fn([1, 2], [3, [5, 6], 4])
// [1, 2, 3, 5, 6, 4]