JavaScript:好的部分-第8章,function.apply()
对于以下代码,基于“JavaScript:the Good Parts”第84页,有人能解释为什么使用[1]和[0]?我知道他们分别为切片提供参数1和0,但这有什么意义JavaScript:好的部分-第8章,function.apply(),javascript,bind,apply,Javascript,Bind,Apply,对于以下代码,基于“JavaScript:the Good Parts”第84页,有人能解释为什么使用[1]和[0]?我知道他们分别为切片提供参数1和0,但这有什么意义 Function.prototype.bind = function (that) { var method = this; var slice = Array.prototype.slice; var args = slice.apply(arguments, [1]); // Why is [1] here?
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.
我相信我了解全局-函数x设计用于提取value属性的值。然后,我们绑定一个具有值的对象属性名/值对,并执行x函数。x函数进入提供的对象,就好像它是该对象的方法一样,并返回value属性的值
我不明白的是这是如何实现的(我注意到Crockford对666的近乎有趣的使用)。提前感谢。apply的第二个参数需要是数组,如果[2]是2,则会发生这种情况 Array.prototype.slice.apply(参数,2); 未捕获类型错误:Function.prototype.apply:参数列表的类型错误
arguments
是一个烘焙属性,它表示发送到类似数组的对象中的函数的所有参数。切片此阵列将删除不需要的部分。在bind的情况下,该
作为参数传递,因此在1之后切片将删除该参数
结果
var args = slice.apply(arguments, [1]); // Why is [1] here?
例如,将获取发送到bind的所有额外参数。bind({},1,2,3,4)将导致args为[1,2,3,4]
接下来,返回一个函数
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
即
将要使用的新范围,方法
是最初从args调用bind的函数。concat
将使用前面检查过的数组,然后添加调用该方法时使用的所有参数,这就是为什么使用[0]
而不是[1]
(其中,已传递且未用作方法的参数)。函数。prototype.apply()
接受两个参数,一个值表示此
和一个参数数组。即使只有一个参数,它也需要一个数组
因此:
几乎相当于:
arguments.slice(1);
我之所以这么说,几乎是因为参数不是一个真正的数组,而且它没有切片方法,这就是为什么你必须用一种时髦的方式来做这件事
正如其他人在评论中所指出的那样,您可以使用call
来简化此操作。call
需要此this
的值,然后是任意数量的附加参数。这意味着您可以改为执行以下操作:
slice.call(arguments, 1);
让我们假设您有一些函数,不管它做什么,并且您将它绑定到一个上下文并传入一些参数
function myFunc(a, b, c) {
}.bind(myContext, arg1, arg2)
现在让我们看看.bind
的作用:
Function.prototype.bind = function (that) {
var method = this;
var slice = Array.prototype.slice;
var args = slice.apply(arguments, [1]); // Why is [1] here?
apply
接受参数上下文[arg1,arg2,…]
。因此slice.apply(arguments,[1])
类似于调用参数。slice(1)
(如注释中所述,您可以使用call
并去掉数组括号。)1
的目的是从1
索引开始切片。传入的是参数[0]
。上下文之后传递给.bind
的任何参数都将包含在此切片中。因此,您可以调用myFunc.bind(myContext,arg1,arg2)
;该切片将args
设置为[arg1,arg2]
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
};
这是由.bind
返回的函数;这是在myFunc时实际调用的函数(这里是一些参数)
直接调用。本例中的切片是整个参数列表;从0切片返回整个列表,转换为数组,以便可以将其传递到外部apply。
太长,读不下去了
第一个参数从1
切片,以删除that
并获取其后面的所有参数。第二个列表从0
切片,以包含传入的所有参数。文档和上下文
请仔细查看、和
apply
将对象作为调用函数的上下文,并向被调用函数发送参数数组的附加可选参数
切片(0)
slice(0)
通常用于将类似数组的对象转换为数组
slice.apply(arguments,[0])
几乎等同于arguments.slice(0),只是它不会更改发送到主函数的参数,而是会生成一个新数组,保证为数组
切片(1)
与上面类似,但将从数组中删除第一个条目。这看起来很愚蠢。如果有什么问题,我会使用slice.call(arguments,1)
。重点是将第一个(0
index)之后的所有参数放入新数组。这与更常见的[].slice.call(arguments,1)相同
。如果参数
是一个实数组,那么您可以编写参数。如果您询问为什么会有括号,这是因为它将参数作为数组应用到函数中。正如@Ian所指出的,使用call允许您使用参数,而无需将参数包装到数组中。
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
};
};