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

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

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

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


当前回答

调用、应用和绑定的另一个示例。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
*/

其他回答

调用、应用和绑定的另一个示例。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
*/

尽管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

K.Scott Allen对这件事有很好的评论。

基本上,它们在处理函数参数的方式上有所不同。

apply()方法与call()方法相同,只是apply(需要一个数组作为第二个参数。数组表示目标方法的参数。"

So:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);

摘要:

call()和apply()都是位于Function.prototype上的方法。因此,它们可以通过原型链在每个函数对象上使用。call()和apply()都可以执行具有指定值this的函数。

call()和apply()之间的主要区别是必须向其中传递参数的方式。在call()与apply(()中,您都将希望作为值的对象作为第一个参数传递为this。其他参数的不同之处如下:

使用call(),您必须正常输入参数(从第二个参数开始)使用apply(),必须传入参数数组。

例子:

让obj={val1:5,值2:10}常量总和=函数(val3,val4){返回this.val1+this.val2+val3+val4;}console.log(summary.apply(obj,[2,3]));//首先,我们在第一个参数中为其赋值//使用apply,我们必须传入一个数组console.log(summary.call(obj,2,3));//通过调用,我们可以单独传入每个参数

为什么我需要使用这些功能?

在javascript中,这个值有时很棘手。该值在执行函数时确定,而不是在定义函数时确定。如果我们的函数依赖于此绑定的权限,我们可以使用call()和apply()来强制执行此行为。例如:

var name='unwantedGlobalName';常量对象={name:“Willem”,sayName(){console.log(this.name);}}let copiedMethod=obj.sayName;//我们将函数存储在copiedmethod变量中copiedMethod();//现在是窗口,unwantedGlobalName将被记录copiedMethod.call(obj);//我们强制这是obj,Willem被记录

我只想在flatline的一篇解释得很好的文章中添加一个简单的例子,这让初学者很容易理解。

func.call(context, args1, args2 );   // pass arguments as "," separated value

func.apply(context, [args1, args2]); // pass arguments as "Array"

我们还使用“Call”和“Apply”方法更改引用,如下面的代码所定义

设Emp1={名称:'X',getEmpDetail:函数(年龄,部门){console.log(`Name:${this.Name}年龄:${Age}部门:${Department}`)}}Emp1.getEmpDetail(23,'交货')//改变“这个”的第一种方法设Emp2={名称:“Y”,getEmpDetail:Emp1.getEmpDetail}Emp2.getEmpDetail(55,“财务”)//使用“Call”和“Apply”更改“this”的第二种方法设Emp3={name:'Emp3_Object',}Emp1.getEmpDetail.call(Emp3,30,'管理员')//这里我们将ref从**Emp1更改为Emp3**对象//现在这将打印“Name=Emp3_Object”,因为它指向Emp3对象Emp1.getEmpDetail.apply(Emp3,[30,'管理员'])