Let's start with an example:
let obj = { a: 'Amazebulous!' };
let otherObj = { a: "That's not a real word!" };
const foo = function() { console.log(this.a); };
let bar = foo.bind(obj);
bar.call(otherObj);
I have looked at MDN and other online resources. There seem to be two different models of bind
's return value.
In the above example, keep in mind that bar
is the returned function, and foo
is the function we'd like to bind to some context. Now, here are the two models I am seeing:
On the first model, bind
returns bar
, which is a higher-order function of foo
. Function bar
is not eternally bound to some context, but it always executes its internal foo
function with the intended context. This is suggested by polyfills (including the first one on MDN) and "implementations" that give you an idea of how things work like:
Function.prototype.bind = function (...args) {
let fn = this;
let context = args.shift();
return function () {
return fn.apply(context, args);
};
};
If this is the correct model, bar
would be a higher-order function that executes foo.apply(obj
whenever (or every time) it (bar
) is executed. That is not the same as saying bar
is permanently bound (indeed, we set bar
's context to otherObj
in the above example), and that is not the same thing as saying foo
is permanently bound (indeed, we can run bind
on foo
again with another context). Although we might say foo
is permanently bound "inside" bar
. If we wanted to bind bar
to obj
permanently, we'd have to additionally run const baz = bar.bind(obj)
. In other words, bar
and foo
are not of the same type. If foo
is a first-order function, then bar
is a second-order function.
On the second model, bind
returns bar
, which is a strange, special function on the same order as foo
and which does what foo
does while being eternally bound to some context.
Which one is correct?
Another way of getting at the heart of the matter would be to answer what is happening on the last line of the original example. On the first model, bar
is invoked while being bound to otherObj
. However, foo
is not bound to otherObj
inside of bar
. Inside of bar
, foo
is bound to obj
. On the second model, JS does something (what?) to (a) not throw an error and (b) ignore call
on bar
so that bar
's context does not change. Put differently:
Why is it that when you invoke bar
(even with call
or apply
), you get a result that behaves as if you're always invoking foo
with the obj
context?
On the first model, that's easy to explain. When you invoke bar
with a call
, you are not affecting the context of the "internal" foo
call in which the context is explicitly set.
On the second model, I don't know how to explain why it is that when you invoke bar
(even with call
), you get a result that behaves as if you're always invoking foo
with the obj
context. It appears that that explanation would have to discuss something special about bar
, but I don't know what it is because I don't really understand the second model. If this model is correct, why doesn't it throw an error when you're seemingly trying to change bar
's context? How does JS silence the call
on bar
?
I am now looking at the spec, and I'm not sure if it helps (I am a beginner; only coding for months). In any case, I'd appreciate clarification on this. It certainly matters for the interpretation of the original code example.
Finally, my question is not answered here. I know what the use of bind
is. But I want to know more details about its return value and how it works (not why it is useful; it's obviously useful).