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).
