16

Is there a way to rebind a function that is already bound to another object via Function.prototype.bind?

var a={};
var b={};
var c=function(){ alert(this===a); };
c(); // alerts false
c=c.bind(a);
c(); // alerts true
c=c.bind(b);
c(); // still alerts true

I know that I can use a different approach and keep a "clean" function for binding, but I just wonder how to reuse an already bound function.

optimizitor
  • 807
  • 13
  • 18

2 Answers2

15

Is there a way to rebind a function that is already bound to another object via Function.prototype.bind?

No. From the ES2015 spec about Function.prototype.bind:

19.2.3.2 Function.prototype.bind ( thisArg , ...args)

[...]

Note 2: If Target is an arrow function or a bound function then the thisArg passed to this method will not be used by subsequent calls to F.

This was already true for earlier versions as well.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Is there any reason you can think of why is that? It's pretty weird that JavaScript tries so hard to be flexible (yet all this `bind` hassle), but doesn't even allow to rebind the value. – Robo Robok Jun 08 '19 at 09:51
  • 1
    `.bind` seems to provide a very strong contract, i.e. it guarantees that no matter how the function is called, `this` will point to the value I defined. If it was possible to again change the value of `this` somehow, `.bind` appears to be less useful. – Felix Kling Jun 08 '19 at 09:54
  • Yeah, it looks like a VERY strong contract. I would like to be able to set my own default binding and allow clients of my code to rebind it though. – Robo Robok Jun 08 '19 at 09:57
  • 1
    You can do this manually by enabling clients to supply the receiver via an argument, and having a default receiver in the event one is not supplied. Just because the language is flexible in one dimension, does not necessarily mean it is flexible in another (indeed why would it?!). In this instance, given that control of the receiver can be delivered in userland, a non-userland guarantee of the receiver is a useful addition to the language. – Ben Aston Apr 28 '20 at 21:56
  • I also wouldn't be surprised if engines implemented bind by just creating another function which wraps a call under the hood and that doesn't suggest an elegant way to rebind. Besides, Ben's point that if you want this functionality you can implement it yourself is a good one. – Peter Gerdes Dec 13 '21 at 16:10
11

What .bind() does is almost the same as this:

function likeBind(fun, thisValue) {
  return function() {
    var args = [].slice.call(arguments, 0);
    return fun.apply(thisValue, args);
  };
}

So:

c = likeBind(c, a);

gives you a bound function. Now, even if you attempt to re-bind, the original bound function still exists in that closure with the value you originally requested to be used as this. Values of variables inside closures can only be changed from inside the closure, so there's nothing you can do to un-bind a bound function like that. You have to start over from the original function.

So, no.

Pointy
  • 405,095
  • 59
  • 585
  • 614