使用call
和apply
调用函数有什么区别?
var func = function() {
alert('hello!');
};
func.apply();
与 func.call();
前述两种方法之间是否存在性能差异?什么时候最好使用call
over apply
,反之亦然?
fn(...input)
,其中input是一个数组。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
使用call
和apply
调用函数有什么区别?
var func = function() {
alert('hello!');
};
func.apply();
与 func.call();
前述两种方法之间是否存在性能差异?什么时候最好使用call
over apply
,反之亦然?
fn(...input)
,其中input是一个数组。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Answers:
不同之处在于apply
,您arguments
可以使用数组作为函数来调用函数。call
需要明确列出参数。有用的助记是“ 甲用于一个 rray和ç为Ç OMMA”。
伪语法:
theFunction.apply(valueForThis, arrayOfArgs)
theFunction.call(valueForThis, arg1, arg2, ...)
从ES6开始,spread
该call
函数还可以使用数组,您可以在此处查看兼容性。
样例代码:
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
[]
叫做数组,{}
叫做对象。
Array.prototype.slice.call(arguments)
或[].slice.call(arguments)
。如果您在数组中有参数,例如在调用具有(几乎)相同参数的另一个函数的函数中,则apply有意义。建议funcname(arg1)
如果需要的话,请使用正常的函数调用,并保存调用并在您确实需要它们的特殊情况下申请。
call
和apply
都带有两个参数。apply' and
call`函数的第一个参数必须是所有者对象,第二个参数分别是数组或逗号分隔的参数。如果您通过null
或undefined
作为第一个参数,则在非严格模式下将其替换为全局对象,即window
斯科特·艾伦(K. Scott Allen)在这件事上写得很好。
基本上,它们在处理函数参数的方式上有所不同。
apply()方法与call()相同,只不过apply()需要一个数组作为第二个参数。该数组代表目标方法的参数。”
所以:
// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
call
而是 第一个参数apply
要回答有关何时使用每个函数的部分,apply
请在不知道要传递的参数数量的情况下,或者如果它们已存在于数组或类似数组的对象(例如arguments
用于转发自己的参数的对象)中,请使用。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)
),否则应该没有任何性能差异。我尚未对其进行测试,因此可能会有差异,但这将取决于浏览器。call
如果您没有数组中的参数,则可能会更快,而如果您没有,则可能会更快apply
。
这是一个很好的助记符。 一个人使用A rays,而一个人则使用一两个参数。当您使用Ç所有你必须ç指望。2-15参数的个数。
apply
所以我将“一个或两个参数”更改为“最多两个参数” 。我不确定为什么会调用apply
或call
没有参数。喜欢一个人看起来正试图为什么在这里找出stackoverflow.com/questions/15903782/...
虽然这是一个老话题,但我只是想指出.call比.apply快一点。我不能告诉你为什么。
参见jsPerf,http: //jsperf.com/test-call-vs-apply/3
[ UPDATE!
]
道格拉斯·克罗克福德(Douglas Crockford)简要提到了两者之间的区别,这可能有助于解释性能差异... http://youtu.be/ya4UHuXNygM?t=15m52s
Apply接受一个参数数组,而Call接受零个或多个单独的参数!啊哈!
.apply(this, [...])
.call(this, param1, param2, param3, param4...)
摘录自Michael Bolin的《闭幕:权威指南》的摘录。它可能看起来有些冗长,但是它充满了很多见识。摘自“附录B:JavaScript概念经常被误解”:
this
调用函数时指的是什么当调用形式的函数时foo.bar.baz()
,该对象foo.bar
称为接收器。调用该函数时,将接收方用作以下值this
:
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
即使obj.addValues
并f
引用相同的函数,它们在调用时的行为也有所不同,因为在每次调用中接收器的值都不同。因此,在调用引用的函数时,this
重要的是要确保在调用时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]);
以下调用是等效的,f
并且obj.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
不能为null
或undefined
调用函数时的值。当将null
或undefined
作为接收者提供给call()
或时apply()
,全局对象将用作接收者的值。因此,先前的代码具有将命名属性添加value
到全局对象的相同的不良副作用。
认为函数不了解为其分配的变量可能会有所帮助。这有助于加强这样的想法,即在调用函数时而不是在定义函数时将绑定此值。
提取结束。
additionalValues
就是obj.addValues
体内没有提及
var f = obj.addValues;
变成var f = obj.addValues.bind(obj)
现在f(20)可以工作,而不必每次都使用调用或应用。
有时一个对象借用另一个对象的功能很有用,这意味着借用对象只是像执行其自己的操作一样简单地执行了lent函数。
一个小代码示例:
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
这些方法对于赋予对象临时功能非常有用。
console.log
检出:什么是console.log以及如何使用它?
调用,应用和绑定的另一个示例。Call和Apply之间的区别很明显,但是Bind的工作方式如下:
}
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
*/
我想展示一个使用'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 *
Call()采用逗号分隔的参数,例如:
.call(scope, arg1, arg2, arg3)
和apply()需要一个参数数组,例如:
.apply(scope, [arg1, arg2, arg3])
以下是一些其他用法示例:http : //blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/
从 Function.prototype.apply()的MDN文档中:
apply()方法使用给定的函数调用
this
值和作为数组(或类似数组的对象)提供的参数。句法
fun.apply(thisArg, [argsArray])
来自Function.prototype.call()的MDN文档:
call()方法使用给定的函数调用
this
值和参数的函数。句法
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'
));
另请参见此Fiddle。
基本区别在于,它call()
接受参数列表,而apply()
接受单个参数数组。
这是我写的一篇小文章:
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()
采用数组中的函数参数。
调用和应用都用于在this
执行函数时强制使用该值。唯一的区别是,call
需要n+1
的参数,其中1 this
和'n' arguments
。apply
只接受两个参数,一个this
是参数数组。
优点我看到apply
过call
的是,我们可以轻松地委派一个函数调用来毫不费力等功能;
function sayHello() {
console.log(this, arguments);
}
function hello() {
sayHello.apply(this, arguments);
}
var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');
观察我们如何轻松地委派hello
到sayHello
使用apply
,但是call
这是很难实现的。
即使call
和apply
achive同样的事情,我觉得有ATLEAST一个地方,你不能使用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()
并apply()
都分别位于方法Function.prototype
。因此,它们可通过原型链在每个功能对象上使用。二者call()
并apply()
可以用的规定值执行功能this
。
call()
和之间的主要区别apply()
是必须将参数传递给它的方式。在call()
和中,apply()
您都将作为值的对象作为第一个参数传递this
。其他参数在以下方面有所不同:
call()
你必须把在参数正常(从第二个参数开始)apply()
您必须传递参数数组。let obj = {
val1: 5,
val2: 10
}
const summation = function (val3, val4) {
return this.val1 + this.val2 + val3 + val4;
}
console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array
console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually
this
有时在javascript中,该值可能很棘手。在不定义功能时执行功能时this
确定的值。如果我们的功能依赖于正确的this
绑定,则可以使用call()
并apply()
强制执行此行为。例如:
var name = 'unwantedGlobalName';
const obj = {
name: 'Willem',
sayName () { console.log(this.name);}
}
let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable
copiedMethod();
// this is now window, unwantedGlobalName gets logged
copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
主要区别在于,使用call可以正常更改范围并传递参数,但是apply可以将参数用作Array来调用它(将它们作为数组传递)。但是就它们在代码中要做的事情而言,它们非常相似。
尽管此函数的语法与apply()的语法几乎相同,但基本区别在于call()接受参数列表,而apply()接受单个参数数组。
因此,正如您所看到的,并没有太大的区别,但是在某些情况下,我们更喜欢使用call()或apply()。例如,看下面的代码,使用apply方法从MDN查找数组中最小和最大的数字:
// 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)
因此,主要区别只是传递参数的方式:
调用:
function.call(thisArg, arg1, arg2, ...);
应用:
function.apply(thisArg, [argsArray]);
让我为此添加一些细节。
这两个调用几乎是等效的:
func.call(context, ...args); // pass an array as list with spread operator
func.apply(context, args); // is same as using apply
只有一个小差异:
- 该
spread
运营商...允许通过迭代args
的列表来调用。- 在
apply
仅接受阵列状 ARGS。
因此,这些调用相互补充。我们期望的迭代,call
作品,我们期待一个类似数组的,apply
作品。
对于既可迭代又类似于数组的对象(如真实数组),从技术上讲,我们可以使用它们中的任何一个,但是应用可能会更快,因为大多数JavaScript引擎在内部对其进行了优化。
a
在申请args数组和c
在args列的调用中。