Search code examples
javascript

What does `bind.bind` mean? A strange way to use JavaScript bind


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]

Solution

  • 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]