连锁和一起申请有什么意义?

时间:2012-07-26 16:48:02

标签: javascript function call apply

我在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 个答案:

答案 0 :(得分:12)

通过call打电话给apply;也就是说,它使用call来调用一个函数(“方法”),它使用apply来进行调用,因为它以(几乎)数组的形式获得了参数。

所以把它分开:

Function.call

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

Function.call.apply

通过对call函数的引用,这是apply的引用。由于apply是通过call对象引用的,因此在调用apply时,this值将是对call函数的引用。

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

所以我们通过call调用apply函数,并将Foo.prototype.method传递给this值,并将“Foo.mmethod”的参数作为参数。

认为它与此基本相同:

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

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

答案 1 :(得分: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]]

答案 2 :(得分: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的{​​{1}}值,后续将填充单个参数。

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

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

答案 3 :(得分: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()arguments函数提供call(),所以现在
    Person.prototype,fullname.call(arguments)
  4. 来自@foxiris的例子

    第一名:

    Function.apply.call(Array,this,[1,2])
    1. 最右边 call()将首先执行
    2. call()的上下文成为apply()的来电者,现在Array.apply()
    3. call()可以接受多个广告,因此它可以向this提供[1, 2]apply(),现在Array.apply(this, [1, 2]);将提供[1, 2] }}
    4. 第二名:

      Function.call.apply(Array,this,[1,2])
      1. 最右边 apply()将首先执行
      2. apply()的上下文成为call()的来电者,现在Array.call()
      3. apply()只能使用一个数组参数,因此它只能向this提供call(),所以现在Array.call(this);,输出为[]
      4. 第三名:

        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} }}。