使用Function.pr原型.apply()和Function.pr原型.call()调用函数有什么区别?

var func = function() {
  alert('hello!');
};

函数.apply();vs func.call();

上述两种方法之间是否存在性能差异?何时最好使用呼叫转移应用,反之亦然?


当前回答

尽管call和apply实现了相同的功能,但我认为至少有一个地方不能使用call,只能使用apply。这是您希望支持继承并希望调用构造函数的时候。

这里有一个函数允许您创建类,它也支持通过扩展其他类来创建类。

function makeClass( properties ) {
    var ctor = properties['constructor'] || function(){}
    var Super = properties['extends'];
    var Class = function () {
                 // Here 'call' cannot work, only 'apply' can!!!
                 if(Super)
                    Super.apply(this,arguments);  
                 ctor.apply(this,arguments);
                }
     if(Super){
        Class.prototype = Object.create( Super.prototype );
        Class.prototype.constructor = Class;
     }
     Object.keys(properties).forEach( function(prop) {
           if(prop!=='constructor' && prop!=='extends')
            Class.prototype[prop] = properties[prop];
     });
   return Class; 
}

//Usage
var Car = makeClass({
             constructor: function(name){
                         this.name=name;
                        },
             yourName: function() {
                     return this.name;
                   }
          });
//We have a Car class now
 var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat

var SuperCar = makeClass({
               constructor: function(ignore,power){
                     this.power=power;
                  },
               extends:Car,
               yourPower: function() {
                    return this.power;
                  }
              });
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6

其他回答

我们可以区分调用和应用方法,如下所示

CALL:单独提供参数的函数。若您知道要传递的参数或并没有要传递的变量,则可以使用call。

APPLY:调用以数组形式提供参数的函数。如果不知道要传递给函数的参数有多少,可以使用apply。

使用applyovercall有一个优点,我们不需要更改参数的数量,只需要更改传递的数组即可。

性能上没有太大差异。但我们可以说,调用比应用更快,因为数组需要在apply方法中求值。

虽然这是一个老话题,但我只是想指出,.call比.apply稍快。我不能告诉你确切的原因。

参见jsPerf,http://jsperf.com/test-call-vs-apply/3


[更新!]

Douglas Crockford简要提到了两者之间的差异,这可能有助于解释性能差异。。。http://youtu.be/ya4UHuXNygM?t=15m52s

Apply接受一个参数数组,而Call接受零个或多个单独的参数!啊哈!

.apply(此,[…])

.调用(this,param1,param2,param3,param4…)

调用、应用和绑定的另一个示例。Call和Apply之间的区别很明显,但Bind的工作原理如下:

Bind返回可以执行的函数的实例第一个参数是“this”第二个参数是逗号分隔的参数列表(如Call)

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/

有时,一个对象借用另一个对象的函数是有用的,这意味着借用对象只需像执行自己的函数一样执行借出函数。

一个小代码示例:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

这些方法对于为对象提供临时功能非常有用。

call()方法调用具有给定this值和第二个参数(用逗号分隔的参数)的函数。

object.someMethod.call( someObject, arguments )

apply()方法与调用相同,只是它使用的第二个参数是一个参数数组。

object.someMethod.apply( someObject, arrayOfarguments )

var汽车={name:“雷诺”,国家:“法国”,showBuyer:函数(firstName,lastName){console.log(`${firstName}${lastName}刚刚从${this.country}购买了${this.name});}}const firstName=“Bryan”;const lastName=“Smith”;car.showBuyer(firstName,lastName);//布莱恩刚从法国买了一辆雷诺constobj={name:“玛莎拉蒂”,国家:“意大利”};car.showBuyer.call(obj,firstName,lastName);//布莱恩·史密斯刚从意大利买了一辆玛莎拉蒂car.showBuyer.apply(obj,[firstName,lastName]);//布莱恩·史密斯刚从意大利买了一辆玛莎拉蒂