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.
精彩评论