通话和申请有什么区别?

使用call和apply来调用函数有什么区别?

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

func.apply();

VS

 func.call(); 

这两种方法之间是否存在性能差异? 什么时候最好使用电话申请,反之亦然?

不同之处在于apply可以让你以argumentsforms调用函数作为数组; call需要显式列出参数。 一个有用的助记符是A一个 rray和Cc omma”。

请参阅MDN的申请和通话文件。

伪语法:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

从ES6开始,也可以使用call函数来spread数组,您可以在这里看到兼容性。

示例代码:

 function theFunction(name, profession) { console.log("My name is " + name + " and I am a " + profession + "."); } theFunction("John", "fireman"); theFunction.apply(undefined, ["Susan", "school teacher"]); theFunction.call(undefined, "Claude", "mathematician"); theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator // Output: // My name is John and I am a fireman. // My name is Susan and I am a school teacher. // My name is Claude and I am a mathematician. // My name is Matthew and I am a physicist. 

K. Scott Allen在这件事上有一个很好的写法 。

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

apply()方法和call()是一样的,除了apply()需要一个数组作为第二个参数。 该数组表示目标方法的参数。“

所以:

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

要回答关于何时使用每个函数的部分,如果您不知道要传递的参数的数量,或者它们已经在数组或类似数组的对象中(如arguments对象来转发您自己的数据),请使用apply参数,否则使用call ,因为不需要将参数包装在数组中。

 f.call(thisObject, a, b, c); // Fixed number of arguments f.apply(thisObject, arguments); // Forward this function's arguments var args = []; while (...) { args.push(some_value()); } f.apply(thisObject, args); // Unknown number of arguments 

当我没有传递任何参数(比如你的例子)时,我更喜欢call因为我正在调用函数。 apply意味着你正在这个函数应用于(不存在的)参数。

不应该有任何性能差异,除非可能如果您使用apply并包裹参数在数组(例如f.apply(thisObject, [a, b, c])而不是f.call(thisObject, a, b, c) )。 我没有testing过,所以可能会有差异,但它会是非常具体的浏览器。 如果你在数组中没有参数,那么call的速度可能会更快,如果你这样做的话, apply会更快。

这是一个很好的助记符。 A pply使用A rrays和A lways需要一个或两个参数。 当你使用C时,你必须C ount参数的数量。

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

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


[ UPDATE! ]

道格拉斯·克罗克福德简要地提到两者之间的差异,这可能有助于解释性能差异… http://youtu.be/ya4UHuXNygM?t=15m52s

应用需要一个参数数组,而Call则需要零个或多个参数! 啊哈!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)

遵循封闭的摘录:迈克尔·波林的权威指南 。 它可能看起来有点冗长,但却饱含了很多洞见。 从“附录B.经常误解的JavaScript概念”:


当一个函数被调用时, this指的是什么

当调用forms为foo.bar.baz()的函数时,对象foo.bar被称为接收者。 当函数被调用时,它被用作这个值的接收器:

 var obj = {}; obj.value = 10; /** @param {...number} additionalValues */ obj.addValues = function(additionalValues) { for (var i = 0; i < arguments.length; i++) { this.value += arguments[i]; } return this.value; }; // Evaluates to 30 because obj is used as the value for 'this' when // obj.addValues() is called, so obj.value becomes 10 + 20. obj.addValues(20); 

如果在函数被调用时没有显式的接收者,那么全局对象就成为接收者。 如第47页的“goog.global”所述,window是在Web浏览器中执行JavaScript时的全局对象。 这导致了一些令人惊讶的行为:

 var f = obj.addValues; // Evaluates to NaN because window is used as the value for 'this' when // f() is called. Because and window.value is undefined, adding a number to // it results in NaN. f(20); // This also has the unintentional side effect of adding a value to window: alert(window.value); // Alerts NaN 

尽pipeobj.addValuesf引用了相同的函数,但是在调用时它们的行为是不同的,因为每个调用中接收者的值是不同的。 由于这个原因,当调用一个引用this函数的函数时,确保this函数在被调用时会有正确的值是非常重要的。 要清楚的是,如果在函数体中没有引用它,那么f(20)obj.addValues(20)将是相同的。

因为函数是JavaScript中的第一类对象,所以它们可以有自己的方法。 所有的函数都有方法call()apply() ,这些方法可以在调用函数的时候重新定义接收者(也就是this引用的对象)。 方法签名如下:

 /** * @param {*=} receiver to substitute for 'this' * @param {...} parameters to use as arguments to the function */ Function.prototype.call; /** * @param {*=} receiver to substitute for 'this' * @param {Array} parameters to use as arguments to the function */ Function.prototype.apply; 

请注意, call()apply()之间的唯一区别是call()接收函数参数作为单独的参数,而apply()接收它们作为单个数组:

 // When f is called with obj as its receiver, it behaves the same as calling // obj.addValues(). Both of the following increase obj.value by 60: f.call(obj, 10, 20, 30); f.apply(obj, [10, 20, 30]); 

以下调用是等同的,因为fobj.addValues指向相同的函数:

 obj.addValues.call(obj, 10, 20, 30); obj.addValues.apply(obj, [10, 20, 30]); 

但是,既然call()apply()使用接收者的值来代替接收者的参数,那么下面的行不通:

 // Both statements evaluate to NaN obj.addValues.call(undefined, 10, 20, 30); obj.addValues.apply(undefined, [10, 20, 30]); 

当一个函数被调用时, this值永远不能为nullundefined 。 当提供nullundefined作为接收者call()apply() ,全局对象将被用作接收者的值。 因此,前面的代码具有向全局对象添加名为value的属性的不良副作用。

将一个函数想象为不知道它所赋予的variables是有帮助的。 这有助于强化这样一个观点,即在函数被调用时这个值将被绑定,而不是在被定义的时候。


提取结束。

有时一个对象借用另一个对象的function是有用的,这意味着借用对象简单地执行借出function就好像它自己一样。

一个小代码示例:

 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 

这些方法对于赋予对象临时function非常有用。

Call()采用逗号分隔的参数,例如:

.call(scope, arg1, arg2, arg3)

和apply()接受一个参数数组,例如:

.apply(scope, [arg1, arg2, arg3])

这里有更多的用法示例: http : //blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

我想展示一个例子,其中使用了'valueForThis'参数:

 Array.prototype.push = function(element) { /* Native code*, that uses 'this' this.put(element); */ } var array = []; array.push(1); array.push.apply(array,[2,3]); Array.prototype.push.apply(array,[4,5]); array.push.call(array,6,7); Array.prototype.push.call(array,8,9); //[1, 2, 3, 4, 5, 6, 7, 8, 9] 

**详情: http : //es5.github.io/#x15.4.4.7 *

Function.prototype.apply()的MDN文档

apply()方法使用给定的this值和作为一个数组(或类似数组的对象)提供的参数来调用一个函数。

句法

 fun.apply(thisArg, [argsArray]) 

Function.prototype.call()的MDN文档

call()方法使用给定的值和单独提供的参数来调用函数。

句法

 fun.call(thisArg[, arg1[, arg2[, ...]]]) 

JavaScript中的Function.apply和Function.call

apply()方法和call()是一样的,除了apply()需要一个数组作为第二个参数。 该数组表示目标方法的参数。


代码示例:

 var doSomething = function() { var arr = []; for(i in arguments) { if(typeof this[arguments[i]] !== 'undefined') { arr.push(this[arguments[i]]); } } return arr; } var output = function(position, obj) { document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>'; } output(1, doSomething( 'one', 'two', 'two', 'one' )); output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [ 'one', 'two', 'two', 'one' ])); output(3, doSomething.call({one : 'Steven', two : 'Jane'}, 'one', 'two', 'two', 'one' )); 

呼叫,应用和绑定的另一个例子。 Call和Apply之间的区别是显而易见的,但是Bind是这样工作的:

  1. 绑定返回一个可以执行的函数的实例
  2. 第一个参数是“ 这个
  3. 第二个参数是逗号分隔的参数列表(如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()接受单个参数数组

这里有一个小小的post,我写到:

http://sizeableidea.com/call-versus-apply-javascript/

 var obj1 = { which : "obj1" }, obj2 = { which : "obj2" }; function execute(arg1, arg2){ console.log(this.which, arg1, arg2); } //using call execute.call(obj1, "dan", "stanhope"); //output: obj1 dan stanhope //using apply execute.apply(obj2, ["dan", "stanhope"]); //output: obj2 dan stanhope //using old school execute("dan", "stanhope"); //output: undefined "dan" "stanhope" 

区别在于call()分别接受函数参数,而apply()接受数组中的函数参数。

我们可以区分呼叫和应用方法如下

CALL:带有自variables的函数。 如果你知道要传递的参数或者没有parameter passing,你可以使用call。

APPLY:使用数组提供的参数来调用一个函数。 如果你不知道有多less参数要传递给函数,你可以使用apply。

有一个使用apply over call的好处,我们不需要改变参数的个数,只有我们可以改变传递的数组。

性能没有太大的差别。 但是由于数组需要在应用方法中进行评估,所以可以说调用比应用更快一些。

这些方法之间的区别是,你想如何传递参数。

“A为arrays和C为逗号”是一个方便的助记符。

当一个函数被执行时,调用和应用两者都被用来强制this值。 唯一的区别是call需要n+1参数,其中1是this'n' argumentsapply只有两个参数,一个是this另一个是参数数组。

我看到的优点是,我们可以很容易地将一个函数调用委托给其他函数。

 function sayHello() { console.log(this, arguments); } function hello() { sayHello.apply(this, arguments); } var obj = {name: 'my name'} hello.call(obj, 'some', 'arguments'); 

观察我们如何轻松地委托你打个hello用,但用这个call很难实现。

即使call apply达到同样的事情,我认为至less有一个地方,你不能使用call但只能使用apply 。 那就是当你想要支持inheritance并想调用构造函数的时候。

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

 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 

主要的区别是使用调用,我们可以改变作用域和传递参数,但应用让你调用使用参数作为一个数组(传递他们作为数组)。 但就他们在代码中做什么而言,他们是非常相似的。

虽然这个函数的语法和apply()几乎是一样的,但是最基本的区别是call()接受一个参数列表,而apply()接受一个单独的参数数组。

所以,正如你所看到的,没有太大的差别,但仍然有我们更喜欢使用call()或apply()的情况。 例如,查看下面的代码,它使用apply方法从MDN中find数组中最小和最大的数字:

 // min/max number in an array var numbers = [5, 6, 2, 3, 7]; // using Math.min/Math.max apply var max = Math.max.apply(null, numbers); // This about equal to Math.max(numbers[0], ...) // or Math.max(5, 6, ...) var min = Math.min.apply(null, numbers) 

所以主要区别就在于我们传递argumenets的方式:

呼叫:

 function.call(thisArg, arg1, arg2, ...); 

应用:

 function.apply(thisArg, [argsArray]);