在JavaScript中的call和apply函数

3
可能重复:

可能重复:
链式调用和apply一起使用的含义是什么?

我发现了一些像这样的代码:

function fun() {
    return Function.prototype.call.apply(Array.prototype.slice, arguments);
}

我知道 JavaScript 中的 callapply,但当它们一起使用时,我感到困惑。
然后我想知道是否
Function.prototype.call.apply(Array.prototype.slice, arguments)

是相同的:

Array.prototype.slice.apply(arguments);

如果不是这样,第一行代码的作用是什么?
2个回答

11

好的,让我们通过替换来解决这个问题。我们从以下内容开始:

Function.prototype.call.apply(Array.prototype.slice, arguments);

我们所知道的:

  1. Function.prototype.call 是一个函数。
  2. callthis 指向 Function.prototype
  3. 我们使用 apply 来改变 callthis 指针为 Array.prototype.slice
  4. arguments应用call 中(而不是作为参数传递)。

因此,以上陈述等同于:

Array.prototype.slice.call(arguments[0], arguments[1], ...);

由此我们可以看出:

  1. Array.prototype.slice是一个函数。
  2. slicethis指针指向Array.prototype
  3. 我们使用call改变slicethis指针为arguments[0]
  4. arguments[1], ...作为参数传递给slice

这与以下表达方式相同:

arguments[0].slice(arguments[1], ...);

这样做的好处是我们可以用一行代码创建一个快速未绑定包装器来包裹 slice 函数。

编辑:更好的创建快速未绑定包装器的方法是按照以下方式进行(请注意,它可能无法在某些旧浏览器中工作,但现在你不必担心这个问题-对于不支持bind的浏览器,你可以始终使用shim):

var slice = Function.prototype.call.bind(Array.prototype.slice);

这与以下代码相同:

function slice() {
    return Function.prototype.call.apply(Array.prototype.slice, arguments);
}

工作原理:

  1. Function.prototype.call 是一个函数。
  2. callthis 指针指向 Function.prototype
  3. 我们使用 bindcallthis 指针更改为 Array.prototype.slice
  4. bind 返回一个函数,其 arguments应用于 call

奖励:如果您像我一样的高度功能编程风格,则会发现这段代码非常有用:

var funct = Function.prototype;
var obj = Object.prototype;
var arr = Array.prototype;

var bind = funct.bind;

var unbind = bind.bind(bind);
var call = unbind(funct.call);
var apply = unbind(funct.apply);

var classOf = call(obj.toString);
var ownPropertyOf = call(obj.hasOwnProperty);
var concatenate = call(arr.concat);
var arrayFrom = call(arr.slice);
  1. 使用这个方法,你可以轻松地使用 call 或者 apply 来创建无限制的封装。
  2. 你可以使用 classOf 方法来获取一个值的内部 [[Class]]
  3. 你可以在 for in 循环中使用 ownPropertyOf 方法。
  4. 你可以使用 concatenate 方法来连接数组。
  5. 你可以使用 arrayFrom 方法来创建数组。

1
Function.prototype.bind.call(Function.prototype.bind, Function.prototype.bind) - Bergi
@Bergi - 这与 Function.prototype.bind.bind(Function.prototype.bind) 相同。=) - Aadit M Shah
这是真的吗?Function.prototype.bind.bind(Function.prototype.bind) === Function.prototype.bind.bind 从你的算法中... @AaditMShah - Stav Alfi

1
通过以下代码行,.apply 使用 .slice 方法作为调用上下文来调用 .call 方法,并将 arguments 集合作为单独的参数传递。
Function.prototype.call.apply(Array.prototype.slice, arguments);

这有效地为我们提供了这个:
Array.prototype.slice.call(arguments[0], arguments[1], arguments[2] /*, etc */);

这意味着.slice()将使用arguments对象中的第一项作为调用上下文,并将其余参数作为普通参数调用。

因此,如果arguments的内容类似于以下内容:

myarray, 0, 5

你最终得到的是这个:
myarray.slice(0, 5)

这基本上是一种不必要做这个的方法:

var arr = arguments[0];
var rest = Array.prototype.slice(arguments, 1);

var result = arr.slice.apply(arr, rest);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接