【问题标题】:What's the purpose of using Function.call.apply in JavaScript?在 JavaScript 中使用 Function.call.apply 的目的是什么?
【发布时间】:2011-09-18 05:57:56
【问题描述】:

我在浏览JavaScript Garden 时偶然发现了用于创建“快速、未绑定的包装器”的 Function.call.apply hack。它说:

另一个技巧是同时使用 call 和 apply 来创建快速、未绑定的包装器。

function Foo() {}

Foo.prototype.method = function(a, b, c) {
    console.log(this, a, b, c);
};

// Create an unbound version of "method" 
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {

    // Result: Foo.prototype.method.call(this, arg1, arg2... argN)
    Function.call.apply(Foo.prototype.method, arguments);
};

我不明白的是,当 Function.apply 足够时,为什么还要麻烦使用 Function.call.apply 。毕竟两者在语义上是等价的。

【问题讨论】:

  • 我确实发布了指向JavaScript Garden 的链接。如果您想直接跳转到包含帖子的部分,请点击here
  • tnx,- 似乎他们暗示这个 hack 可以加快速度。但是,真的,只是不要使用它
  • @Aadit Function.call.applyFunction.apply 在这里不能相同,因为前者应用 Function.call 而第二个尝试应用 Function 构造函数。我的答案中有详细信息,但我敢打赌,如果 Ivo Wetzel 来回答这个问题,他会更加雄辩和易于理解。这是相当深刻的东西。我同意这可能不是你应该使用的东西,除非你想让同事花费,哦我不知道,一个 半小时 试图理解它。 :)
  • 我认为Function.call 实际上有点误导。它真的应该是Function.prototype.call,因为Function.call 可能会被覆盖。 Function 毕竟只是一个函数对象。 (是的,这很难理解)
  • @Pubbaa80 虽然Function.call===Function.prototype.call 没有讨厌的东西,但我完全同意你的看法。但请注意JSON.stringify(Object.getOwnPropertyDescriptor(Function.prototype, "call")) 返回{"writable":true,"enumerable":false,"configurable":true},所以真正邪​​恶的也可以覆盖 Function.prototype.call。哎呀。

标签: javascript


【解决方案1】:

不,Function.call.applyFunction.apply 在这种情况下并不相同。

假设原来的调用者调用

Foo.method(t, x, y, z)

同时调用和应用,就像在 JavaScript Garden 代码中一样。这会执行

Function.call.apply(Foo.prototype.method, arguments);

这是(松散地,用数组表示法写arguments):

Function.call.apply(Foo.prototype.method, [t, x, y, z]);

使用this==Foo.prototype.method 调用Function.call

Foo.prototype.method.call(t, x, y, z)

它调用Foo.prototype.method 并将this 设置为t 和参数xyz。甜的。就像在 cmets 中一样。我们已经成功地制作了一个包装器。

现在假设你离开时只说Function.apply 而不是Function.call.apply,你声称它在语义上是等价的。你会有

Function.apply(Foo.prototype.method, arguments);

这是(松散地)

Function.apply(Foo.prototype.method, [t, x, y, z]);

它调用函数Function(啊!),this 设置为Foo.prototype.method,参数txyz

完全不一样。

【讨论】:

  • 但是这种包装的目的是什么?
  • 目的是调用Foo.prototype.method而不绑定到Foo的实例。相反,您传入 您自己的 值以用作Foo.prototype.method 内的this 的值。你为什么要这样做?也许你想做一些函数式编程,而你想要映射或减少或过滤的函数恰好是一个绑定方法。如果您不希望它绑定到对象,则调用“未绑定包装器”。虽然这是一个奇怪的术语,因为您最终将此方法绑定到您自己的对象(但您可以忽略它......)
  • 好的,据我了解,以下语句是等效的: Function.call.apply(Foo.prototype.method, arguments); Foo.prototype.method.apply(arguments[0], Array.prototype.slice.call(arguments, 1));它们都可以被替换以创建未绑定的包装器。然而,第一种方法更短、更快、更直观。太棒了!
【解决方案2】:

这意味着您可以在另一个对象上使用来自一个对象的方法。

一个很好的例子是所有函数都有的参数变量,它就像一个数组而不是数组,所以你可以在它上面调用数组的方法:

Array.prototype.join.call(arguments, ",");

【讨论】:

  • 但是apply 位在原始问题中的作用是什么?
  • @CameronSkinner:函数对象的apply 方法执行该函数,在该执行中将第一个参数视为this,将第二个参数视为argumentsfn.apply(a, [b, c]) 等价于 fn.call(a, b, c)
猜你喜欢
  • 2015-04-08
  • 2018-02-19
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
相关资源
最近更新 更多