For the following code, based on page 84 of "JavaScript: The Good Parts", can someone explain why [1] and [0] are used? I understand that they're supplying the arguments 1 and 0 to slice, respectively, but what's the point of that?
Function.prototype.bind = function (that) {
var method = this;
var slice = Array.prototype.slice;
var args = slice.apply(arguments, [1]); // Why is [1] here?
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
};
var x = function () {
return this.value;
}.bind({ value: 666 });
console.log(x()); // Returns 666.
I believe I understand the big picture - the function x has been designed to extract the value of the value property. We then bind an object that has a value property name/value pair and execute the x function. The x function reaches into the supplied object, as if it where a method of that object, and returns the value of the value property.
What I do not understand is how this is accomplished (I note Crockford's quasi-amusing use of 666 ). Thanks in advance.
The second argument for apply needs to be an array, if [2] were 2 instead, this would happen
Array.prototype.slice.apply(arguments, 2); Uncaught TypeError: Function.prototype.apply: Arguments list has wrong type
arguments
is a baked in property which represents all of the arguments send to a function in an array like object. slicing this array will remove unwanted parts. In the case of bind, that
is passed as an argument so slicing after 1 will remove that.
As a result
var args = slice.apply(arguments, [1]); // Why is [1] here?
Will take all of the extra arguments sent to bind, for example .bind({},1,2,3,4) will result in args being [1,2,3,4]
Next, a function is returned
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
that
is going to be the new scope to use, method
is the function that bind was originally called from, args.concat
is going to take the previous array examined, and then add in all of the arguments which the method was called with, which is why [0]
was used as opposed to [1]
(where that
was passed and was not being used as an argument for the method).
Function.prototype.apply()
takes 2 arguments, a value for this
and an array of arguments
. Even if there is only one argument, it expects an array.
So:
slice.apply(arguments, [1]);
is almost equivalent to:
arguments.slice(1);
I say almost because arguments
is not a real array, and it does not have a slice method, which is why you have to do this the funky way.
As others note in the comments, you can use call
instead to make this cleaner. call
expects a value for this this
and then any number of additional individual arguments. Which means you can instead do:
slice.call(arguments, 1);
Let's assume you have some function, it doesn't matter what it does, and you are binding it to a context and passing some arguments in.
function myFunc(a, b, c) {
}.bind(myContext, arg1, arg2)
Now let's look at what .bind
does:
Function.prototype.bind = function (that) {
var method = this;
var slice = Array.prototype.slice;
var args = slice.apply(arguments, [1]); // Why is [1] here?
apply
takes the arguments context, [arg1, arg2, ...]
. So slice.apply(arguments, [1])
is like calling arguments.slice(1)
. (As noted in the comments, you could use call
and drop the array brackets.) The purpose of the 1
is to start the slice from the 1
index. that
which is passed in is arguments[0]
. Any arguments passed to .bind
after the context would be included in this slice. So you might call myFunc.bind(myContext, arg1, arg2)
; that slice
would set args
to [arg1, arg2]
.
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
};
This is the function that gets returned by .bind
; this is the function that will actually be called when myFunc(some, params, here)
is called directly. The slice
in this case is the entire arguments list; slicing from 0 returns the whole list, converted to an array, so that it can be passed to the outer apply.
The first arguments are sliced from 1
to drop that
and get all the arguments after it. The second list is sliced from 0
to include ALL the arguments passed in.
Take a closer look at Function.prototype.apply() , the arguments object , and the slice function .
apply
takes an object as the context to call a function, with an additional optional parameter of an array of arguments to send to the called function.
slice(0)
is often used to covert array-like objects into arrays.
slice.apply(arguments, [0])
is nearly equivalent to arguments.slice(0), except that it will not alter the arguments sent to the main function, but will result in a new array, guaranteed to be an array.
Similar to above, but will remove the first entry from the array.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.