Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

From the MDN:

The bind() method creates a new function that, when called, has its this keyword set to the provided value

And I can happily see it working in this example:

(function () {
   console.log(this);
}).bind({foo:"bar"})();

which logs Object { foo="bar"}

But if I chain another bind call, or even a "call" call, I'm still getting the function invoked with "this" assigned to the object passed to the first bind. Examples:

(function () {
   console.log(this);
}).bind({foo:"bar"}).bind({oof:"rab"})();

&

(function () {
   console.log(this);
}).bind({foo:"bar"}).call({oof:"rab"});

both log Object { foo="bar"} instead of what I would expect: Object { oof="rab"}

No matter how many bind calls I chain, only the first one seems to have an effect.

Why?

EDIT: This might help, just found out jQuery's version is behaving the same way! :O

jQuery.proxy(
  jQuery.proxy(function() {
      console.log(this);
  },{foo:"bar"})
,{oof:"rab"})();

logs Object { foo="bar"} Thanks!

share|improve this question
3  
Weird! Good question –  Jivings yesterday
2  
Great question. So good, in fact, it's knocked the ES5 spec offline. I think you've broken JavaScript. –  joews yesterday
2  
@joews seems fair, Javascript's broken me a few times too ! haha –  Ruben Serrate yesterday
3  
what might the use of chaining bind() be? –  tomasb yesterday
2  
@tomasb It came up by using the observer pattern. The function I attached was the result of a bind call, and in the "observable" notify method I was using "call" to execute that function. I just wanted to make sure the first value was preserved and then this question came to my mind. –  Ruben Serrate yesterday

4 Answers 4

up vote 24 down vote accepted

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 ask, what is the reason for such an arbitrary restriction?

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 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:

Function.prototype.bind = function(ctxt) {
    var fn = this;
    return function bound_fn() {
        return fn.call(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 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);
share|improve this answer
    
Genius!! "is burned in when the function is created" is the key! And it's being burned in by a lovely closure. One have to love Javascript! Honestly! –  Ruben Serrate yesterday

I found this line on MDN:

The bind() function creates a new function (a bound function) with the same function body (internal call property in ECMAScript 5 terms) as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(), which cannot be overridden.

so maybe it's really cannot be overridden once it is set.

share|improve this answer
    
Would it be too cheeky to ask why it cannot be overriden? –  Ruben Serrate yesterday
2  
that's something i don't know, and i hope some wise person will bring light on this –  igor milla yesterday
    
Upvoted, will accept if that wise person doesn't show up :) –  Ruben Serrate yesterday

Okay, this is going to be mostly speculation but I'll try and reason through it.

The ECMAScript specification (which is currently down) states the following for the bind function (emphasis my own):

15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]])

The bind method takes one or more arguments, thisArg and (optionally) arg1, arg2, etc, and returns a new function object by performing the following steps:

  1. Let Target be the this value.
  2. If IsCallable(Target) is false, throw a TypeError exception.
  3. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
  4. Let F be a new native ECMAScript object .
  5. Set all the internal methods, except for [[Get]], of F as specified in 8.12.
  6. Set the [[Get]] internal property of F as specified in 15.3.5.4.
  7. Set the [[TargetFunction]] internal property of F to Target.
  8. Set the [[BoundThis]] internal property of F to the value of thisArg.
  9. Set the [[BoundArgs]] internal property of F to A.
  10. Set the [[Class]] internal property of F to "Function".
  11. Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1.
  12. Set the [[Call]] internal property of F as described in 15.3.4.5.1.
  13. Set the [[Construct]] internal property of F as described in 15.3.4.5.2.
  14. Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3.
  15. If the [[Class]] internal property of Target is "Function", then a. Let L be the length property of Target minus the length of A. b. Set the length own property of F to either 0 or L, whichever is larger.
  16. Else set the length own property of F to 0.
  17. Set the attributes of the length own property of F to the values specified in 15.3.5.1.
  18. Set the [[Extensible]] internal property of F to true.
  19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
  20. Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
  21. Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.
  22. Return F

And when you call a function on your Object that was created with bind:

15.3.4.5.1 [[Call]]

When the [[Call]] internal method of a function object, F, which was created using the bind function is called with a this value and a list of arguments ExtraArgs, the following steps are taken:

  1. Let boundArgs be the value of F’s [[BoundArgs]] internal property.
  2. Let boundThis be the value of F’s [[BoundThis]] internal property.
  3. Let target be the value of F’s [[TargetFunction]] internal property.
  4. Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list ExtraArgs in the same order.
  5. Return the result of calling the [[Call]] internal method of target providing boundThis as the this value and providing args as the arguments

Call specifies how every function is called. And somewhat resembles the JavaScript call:

someFunction.[[call]](thisValue, arguments) {

}

However when [[call]] is used on a bound function, the thisValue is overridden with the value of [[BoundThis]]. In the case of calling bind a second time, the thisValue that you attempt to override the first with is replaced by [[BoundThis]], essentially incurring no effect whatsoever on the value of thisValue:

boundFunction.[[call]](thisValue, arguments) {
  thisValue = boundFunction.[[BoundThis]];
}

You'll notice that if you try and use call or apply then they will also have no effect because their attempt to override the thisValue property will be reversed when [[call]] invokes the next function.

share|improve this answer

torazaburo's excellent answer gave me an idea. It would be possible for a bind-like function, instead of baking the receiver (this) into the call inside a closure, to put it as a property on the function object and then use it when the call is made. That would allow a rebind to update the property before the call is made, effectively giving the rebind results that you expected.

For example,

function original_fn() {
    console.log(this);
}

Function.prototype.rebind = function(obj) {
    var fn = this;
    var bound = function func() {
        fn.call(func.receiver, arguments);
    };
    bound.receiver = obj;
    bound.rebind = function(obj) {
        this.receiver = obj;
        return this;
    };
    return bound;
}

var bound_fn = original_fn.rebind({foo: 'bar'});

bound_fn();

var rebound_fn = bound_fn.rebind({fred: 'barney'});

rebound_fn();

The output is as follows. (I originally had this as a code snippet, but apparently console.log doesn't work in code snippets. The output below was obtained by running the code through node.js.)

{ foo: 'bar' }
{ fred: 'barney' }

Note that the first call to rebind is calling the one that was added to Function.prototype since it is being called on ordinary function original_fn, but the second call is calling the rebind that was added as a property to the bound function (and any subsequent calls will call this one, as well). That rebind simply updates receiver and returns the same function object.

It was possible to access the receiver property within the bound function by making it a named function expression.

share|improve this answer
    
In code snippets you can use document.writeln. –  torazaburo 4 hours ago
    
Very creative, +1. –  torazaburo 17 mins ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.