JavaScript:好的部分 - 第8章,function.apply()

时间:2014-10-28 20:39:47

标签: 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?

  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 旨在提取属性的值。然后,我们绑定一个具有属性名称/值对的对象,并执行 x 函数。 x 函数到达提供的对象,就好像它是该对象的方法一样,并返回属性的值。

我不明白这是如何实现的(我注意到Crockford对 666 的准有趣使用)。提前谢谢。

4 个答案:

答案 0 :(得分:3)

apply的第二个参数需要是一个数组,如果[2]为2,则会发生这种情况

  

Array.prototype.slice.apply(arguments,2);   未捕获的TypeError:Function.prototype.apply:参数列表的类型错误

arguments是一个烘焙的属性,它表示发送给像object这样的数组中的函数的所有参数。切片此数组将删除不需要的部分。在绑定的情况下,that作为参数传递,因此在1之后切片将删除它。

结果

var args = slice.apply(arguments, [1]); // Why is [1] here?

将所有发送的额外参数绑定到绑定,例如.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?
};

that将成为新的使用范围,method是最初调用bind的函数,args.concat将检查先前的数组,然后添加在调用该方法的所有参数中,这就是为什么使用[0]而不是[1](其中that被传递并且未被用作方法的参数的原因)。

答案 1 :(得分:0)

Function.prototype.apply()需要2个参数,this的值和arguments数组。即使只有一个参数,它也需要一个数组。

所以:

slice.apply(arguments, [1]);

几乎相当于:

arguments.slice(1);

我说几乎是因为arguments不是真正的数组,并且它没有切片方法,这就是为什么你必须以时髦的方式做到这一点。

正如其他人在评论中指出的那样,您可以使用call来改善它。 call期望此this的值,然后是任意数量的其他单个参数。这意味着您可以改为:

slice.call(arguments, 1);

答案 2 :(得分:0)

让我们假设你有一些功能,它的作用并不重要,你将它绑定到一个上下文并传递一些参数。

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接受参数context, [arg1, arg2, ...]。因此slice.apply(arguments, [1])就像调用arguments.slice(1)一样。 (如评论中所述,您可以使用call并删除数组括号。)1的目的是从1索引开始切片。传入的thatarguments[0]。在上下文之后传递给.bind的任何参数都将包含在此切片中。所以你可以打电话给myFunc.bind(myContext, arg1, arg2); slice会将args设置为[arg1, arg2]

  return function () { 
    return method.apply(that, args.concat(slice.apply(arguments, [0]))); // Why is [0] here?
  };
};

这是由.bind返回的函数;这是直接调用myFunc(some, params, here)时实际调用的函数。在这种情况下,slice是整个参数列表;从0切片返回整个列表,转换为数组,以便它可以传递到外部apply.


TL; DR

第一个参数从1切换到删除that并获取其后的所有参数。第二个列表从0切片,包括传入的所有参数。

答案 3 :(得分:0)

文档和上下文

仔细查看Function.prototype.apply()arguments objectslice function

apply将一个对象作为调用函数的上下文,并使用一个参数数组的附加可选参数发送给被调用函数。

片(0)

slice(0)通常用于将类似数组的对象转换为数组。

slice.apply(arguments, [0])几乎等于arguments.slice(0),除了它不会改变发送到main函数的参数,但会产生一个新的数组,保证是一个数组。

切片(1)

与上面类似,但会删除数组中的第一个条目。