开发者

explanation about prototype.js function binding code

开发者 https://www.devze.com 2022-12-27 20:31 出处:网络
From: http://ejohn.org/apps/learn/#2 Function.prototype.bind = function(){ var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();

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 neces开发者_如何学JAVAsary? 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)));


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


Old post but a newer approach ;)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

This is a very good example to explain. Run it and check the console log. Then modify the code to leave out

[].slice.call(arguments)

You will see that the console.log of the execution of x(1,2,3) is not showing up the arguments anymore. This is because the arguments objects is a local variable within all functions. That might sound a bit confusing, but what it means is basically:

var x = func.bind(obj,1,2,3);

Returns this function internally:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

So it is more of a template for the function.

When you do now run it like:

x(4,5,6)

This will be ran:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

with a special arguments object = {0:4,1:5,2:6} , which can be converted into an array using [].slice.call where arguments is a local object, that is automatically beeing assigned during the invokation of the function.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号