8

我在 jsGarden 中遇到了这段代码,我无法理解链接callapply在一起的含义。两者都将使用给定的上下文对象执行函数,为什么它可以被链接?

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);
};
4

4 回答 4

12

它正在调用callvia apply; 也就是说,它call用于调用函数(“方法”),并且apply用于进行调用,因为它以(几乎)数组的形式获取参数。

所以把它拆开:

Function.call

这是call()对所有 Function 实例上可用的函数的引用,继承自 Function 原型。

Function.call.apply

call这是通过对函数的引用对apply. 因为apply是通过call对象引用的,所以在调用时,applythis将是对call函数的引用。

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

因此,我们call通过 调用函数,并将其作为值apply传递给“Foo.mmethod”作为参数。Foo.prototype.methodthis

觉得和这个效果基本一样:

Foo.method = function() {
  var obj = arguments[0], args = [].slice.call(arguments, 1);
  Foo.prototype.method.apply(obj, args);
}

但我得试一试才能确定。编辑是的,似乎就是这样。因此,我可以将该技巧的要点总结为一种apply()在所需this值是包含参数的数组的第一个元素时调用的方法。换句话说,通常当您调用时,apply()您已经获得了所需的this对象引用,并且您已经获得了参数(在数组中)。但是,这里的想法是您将所需this的参数作为参数传递,因此需要将其分离出来以便进行调用apply。就我个人而言,我会像在我的“翻译”中那样做,因为它(对我而言)不那么令人费解,但我想人们可以习惯它。根据我的经验,这种情况并不常见。

于 2012-07-26T16:50:26.820 回答
2

我认为代码应该是这样的:

function Foo() {}

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

Foo.method = function() {

 //Notice this line:
 Function.apply.call(Foo.prototype.method, this, arguments);
};

然后

Foo.method(1,2,3) => function Foo() {} 1 2 3

其他示例:

Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2])  => [[1, 2]]
于 2015-03-02T12:29:14.323 回答
1

apply确实将数组作为第二个参数,call采用单个参数。

 // lets take call,
 var callfn = Function.prototype.call;
 // an ordinary function from elsewhere
 var method = Foo.prototype.method;
 // and apply the arguments object on it:
 callfn.apply(method, arguments);

因此,第一arguments项将是 的this值,method随后将填充单个参数。

结果是构造函数method上的一个静态函数Foo,它将一个Foo实例(或类似的东西)作为第一个参数并将原型method应用于它。一个可能的用例是定义一个Object.hasOwnProperty函数,该函数通常仅作为Object.prototype.hasOwnProperty.

method最终,如果您需要将它应用于 a) 不继承它或 b) 覆盖它的对象,它会使一个“原型”和一个“调用”的调用更短。

于 2012-07-26T16:53:14.503 回答
1
Person.prototype.fullname = function(joiner, options) {
  options = options || { order: "western" };
  var first = options.order === "western" ? this.first : this.last;
  var last =  options.order === "western" ? this.last  : this.first;
  return first + (joiner || " ") + last;
};

// Create an unbound version of "fullname", usable on any object with 'first'
// and 'last' properties passed as the first argument. This wrapper will
// not need to change if fullname changes in number or order of arguments.
Person.fullname = function() {
  // Result: Person.prototype.fullname.call(this, joiner, ..., argN);
  return Function.call.apply(Person.prototype.fullname, arguments);
};

来自 Javascript Garden 的代码。

请注意,它声明了

Function.call.apply(Person.prototype.fullname, arguments);
会变成这样:

Person.prototype.fullname.call(this, joiner, ..., argN);

这意味着首先执行apply()函数,然后执行call()函数。

模式:最右边 call() / apply()的将首先被执行

  1. 所以最正确的 apply()将首先被执行
  2. 的上下文apply()成为call()函数的调用者,所以现在
    Person.prototype,fullname.call()
  3. apply()只能接受一个参数数组,所以apply()提供argumentscall()函数,所以现在
    Person.prototype,fullname.call(参数)

来自@foxiris 的示例

第一个:

Function.apply.call(Array,this,[1,2])
  1. 正确 call()的将首先被执行
  2. 的上下文call()成为 的调用者apply(),所以现在Array.apply()
  3. call()可以接受多个参数,所以它可以提供和thisto [1, 2]apply()所以 now Array.apply(this, [1, 2]);,它将输出[1, 2]

第二个:

Function.call.apply(Array,this,[1,2])
  1. 正确 apply()的将首先被执行
  2. 的上下文apply()成为 的调用者call(),所以现在Array.call()
  3. apply()只能接受一个数组参数,所以它只能提供给thiscall()所以现在Array.call(this);,输出是[]

第三个:

Function.call.call(Array,this,[1,2])
  1. 正确 call()的将首先被执行
  2. (最右边的)的上下文call()变成了(右边第二个)的调用者call(),所以现在Array.call()
  3. 可以接受多个参数,call()所以它可以提供this[1, 2]给另一个call(),所以现在Array.call(this, [1, 2]);,输出是[[1, 2]]
于 2018-03-03T02:14:13.117 回答