1

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

w-h-a
  • 37
  • 3
  • 2
    You should generally believe MDN. – Barmar Mar 16 '21 at 16:04
  • 3
    What do you mean by "`bind` returns `bar`"? `bar` is a variable, it's not something that can be returned. `bind` returns a bound function object, and it's assigned to `bar`. – Barmar Mar 16 '21 at 16:07
  • I don't understand why this was closed. – w-h-a Mar 16 '21 at 16:35
  • Your definition of `bind()` ignores the actual arguments that are supplied when you call the bound function. Notice how the polyfill in MDN concatenates `args` with `arguments`. – Barmar Mar 16 '21 at 17:37
  • I would like to answer the question, but I've read it over and over and I can't figure out what distinction you're trying to make between the two models. It all seems to revolve around your notion of "permanently bound", which you haven't defined. Does that come from a spec? – Barmar Mar 16 '21 at 18:56
  • When you say "You should generally believe MDN" do you mean that I should assume it essentially works as the polyfills specify? Thanks. – w-h-a Mar 16 '21 at 21:08
  • 1
    Yes. The official spec is very hard to read because it's very abstract. MDN explanations and polyfills are more understandable. It might gloss over some details occasionally, but they're rarely critical. – Barmar Mar 16 '21 at 21:10
  • But what I really meant is that if you found other online resources like tutorials, they usually won't be as good as MDN. – Barmar Mar 16 '21 at 21:11

0 Answers0