views:

140

answers:

1

From: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

Can anyone tell me why the second return is necessary (before fn.apply)?

Also, can anyone explain why args.concat is necessary? Why wouldn't it be re-written as:

fn.apply(object, args)

instead of

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));
+1  A: 

The second return is necessary because otherwise we will lose any return value from the bound function.

You may already know this, but doesn't hurt to mention. If we don't wrap fn.apply inside another function, then we are directly calling the function fn which is sub-optimal, as bind is only supposed to set the execution context (what should this refer to inside the function), and not invoke it.

Javascript methods can be invoked by calling the call or apply method on them. Here's a small example:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

The outer function in Prototype's bind() is supposed to work like an invisible wrapper around the bound function. Thus any arguments that are passed to the wrapper should be passed to the bound function as well, and it must return any value that the bound function returns, which is why the return statement is there.

The reason for doing args.concat inside fn.apply is different and it's not optional. bind in Prototype allows you to prepend arguments to the bound function.

args represents the arguments that were passed when we called bind on the function. arguments represents the arguments that were passed when we called the bound function. We're basically concatenating two arrays there.

From the above example:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49
Anurag