Chaining .bind() calls in JavaScript. Unexpected result?

It is tempting to think of bind as somehow modifying a function to use a new this. In this (incorrect) interpretation, people think of bind as adding some kind of magic flag to the function telling it to use a different this next time it’s called. If that were the case, then it should be possible to “override” and change the magic flag. And one would then ask, what is the reason for arbitrarily restricting the ability to do so?

But in fact, that’s not how it works. bind creates and returns a new function which when called invokes the first function with a particular this. The behavior of this newly created function, to use the specified this to call the original function, is burned in when the function is created. It cannot be changed any more than the internals of any other function returned by a function could be changed after the fact.

It may help to look at a real simple implementation of bind:

// NOT the real bind; just an example
Function.prototype.bind = function(ctxt) {
    var fn = this;
    return function bound_fn() {
        return fn.apply(ctxt, arguments);
    };
}

my_bound_fn = original_fn.bind(obj);

As you can see, nowhere in bound_fn, the function returned from bind, does it refer to the this with which the bound function was called. It’s ignored, so that

my_bound_fn.call(999, arg)            // 999 is ignored

or

obj = { fn: function () { console.log(this); } };
obj.fn = obj.fn.bind(other_obj);
obj.fn();                            // outputs other_obj; obj is ignored

So I can bind the function returned from bind “again”, but that is not rebinding the original function; it’s merely binding the outer function, which has no effect on the inner function, since it is already set up to call the underlying function with the context (this value) passed to bind. I can bind again and again but all I end up doing is creating more outer functions which may be bound to something but still end up calling the innermost function returned from the first bind.

Therefore, it is somewhat misleading to say that bind “cannot be overridden”.

If I want to “rebind” a function, then I can just do a new binding on the original function. So if I’ve bound it once:

function orig() { }
my_bound_fn = orig.bind(my_obj);

and then I want to arrange for my original function to be called with some other this, then I don’t rebind the bound function:

my_bound_fn = my_bound_fn.bind(my_other_obj);     // No effect

Instead, I just create a new function bound to the original one:

my_other_bound_fn = orig.bind(my_other_obj);

Leave a Comment