Joh*_*uff 3012 javascript performance function dynamic
使用call和apply调用函数有什么区别?
var func = function() {
alert('hello!');
};
Run Code Online (Sandbox Code Playgroud)
func.apply(); VS func.call();
上述两种方法之间是否存在性能差异?当它最好使用call过apply,反之亦然?
fla*_*ine 3561
不同之处在于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 operatorRun Code Online (Sandbox Code Playgroud)
not*_*oop 222
基本上,他们在处理函数参数方面有所不同.
apply()方法与call()相同,但apply()需要一个数组作为第二个参数.数组表示目标方法的参数."
所以:
// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
Run Code Online (Sandbox Code Playgroud)
Mat*_*ley 155
要回答关于何时使用每个函数的部分,请使用,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
Run Code Online (Sandbox Code Playgroud)
当我没有传递任何参数时(比如你的例子),我更喜欢call因为我正在调用函数.apply意味着你将函数应用于(不存在的)参数.
应该没有任何性能差异,除非您使用apply并包装数组中的参数(例如,f.apply(thisObject, [a, b, c])而不是f.call(thisObject, a, b, c)).我没有测试它,所以可能存在差异,但它将是非常特定于浏览器的.call如果你没有数组中的参数,那么可能会更快,如果你这样做的话,速度apply会更快.
Joe*_*Joe 109
这是一个很好的助记符. 一个 pp 使用A rrays和A lways需要一个或两个参数.当您使用Ç所有你必须ç 'mount的参数的个数.
kma*_*eny 91
虽然这是一个古老的话题,但我只想指出.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...)
Dom*_*kis 75
遵循Michael Bolin的Closure:The Definitive Guide的摘录.它可能看起来有点冗长,但它充满了很多洞察力.从"附录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);
Run Code Online (Sandbox Code Playgroud)
如果在调用函数时没有显式接收器,则全局对象成为接收器.如第47页的"goog.global"中所述,窗口是在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
Run Code Online (Sandbox Code Playgroud)
即使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;
Run Code Online (Sandbox Code Playgroud)
请注意,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]);
Run Code Online (Sandbox Code Playgroud)
以下调用是等效的,f并且obj.addValues引用相同的函数:
obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);
Run Code Online (Sandbox Code Playgroud)
然而,由于没有call()也不apply()使用它自己的接收器来替代接收机参数时,它是不确定的值,以下将无法正常工作:
// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);
Run Code Online (Sandbox Code Playgroud)
的价值this永远不能null或undefined当一个函数被调用.当null或undefined作为接收器提供call()或时apply(),全局对象用作接收器的值.因此,前面的代码具有将名称属性添加value到全局对象的相同的不良副作用.
将函数视为不知道它所分配的变量可能会有所帮助.这有助于强化这样一种观点,即在调用函数时,而不是在定义函数时,它的值将被约束.
提取物结束.
小智 33
有时一个对象借用另一个对象的函数是有用的,这意味着借用对象只是执行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
Run Code Online (Sandbox Code Playgroud)
这些方法对于为对象提供临时功能非常有用.
Mah*_*esh 25
Call,Apply和Bind的另一个例子.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
*/
Run Code Online (Sandbox Code Playgroud)
小智 23
我想展示一个例子,其中使用'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]
Run Code Online (Sandbox Code Playgroud)
**详情:http://es5.github.io/#x15.4.4.7*
小智 20
Call()采用逗号分隔的参数,例如:
.call(scope, arg1, arg2, arg3)
和apply()接受一个参数数组,例如:
.apply(scope, [arg1, arg2, arg3])
这里有几个用法示例:http: //blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/
Joh*_*ers 19
从Function.prototype.apply()上的MDN文档:
apply()方法调用具有给定
this值的函数和作为数组(或类数组对象)提供的参数.句法
Run Code Online (Sandbox Code Playgroud)fun.apply(thisArg, [argsArray])
从Function.prototype.call()上的MDN文档:
call()方法调用具有给定
this值的函数和单独提供的参数.句法
Run Code Online (Sandbox Code Playgroud)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'
));Run Code Online (Sandbox Code Playgroud)
另见这个小提琴.
Dan*_*Dan 10
这是一篇小帖子,我写道:
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"
Run Code Online (Sandbox Code Playgroud)
和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 individuallyRun Code Online (Sandbox Code Playgroud)
在 javascript 中,该this值有时可能很棘手。的值是在执行函数时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 loggedRun Code Online (Sandbox Code Playgroud)
主要区别是,使用 call,我们可以像平常一样更改范围并传递参数,但 apply 允许您使用参数作为数组来调用它(将它们作为数组传递)。但就它们在代码中执行的操作而言,它们非常相似。
虽然该函数的语法与 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)
Run Code Online (Sandbox Code Playgroud)
所以主要的区别只是我们传递参数的方式:
调用:
function.call(thisArg, arg1, arg2, ...);
Run Code Online (Sandbox Code Playgroud)
申请:
function.apply(thisArg, [argsArray]);
Run Code Online (Sandbox Code Playgroud)
我只是想在flatline的一篇解释得很清楚的帖子中添加一个简单的例子,这使得初学者很容易理解。
func.call(context, args1, args2 ); // pass arguments as "," separated value
func.apply(context, [args1, args2]); // pass arguments as "Array"
Run Code Online (Sandbox Code Playgroud)
我们还使用“Call”和“Apply”方法来更改 参考,如下面的代码中所定义
func.call(context, args1, args2 ); // pass arguments as "," separated value
func.apply(context, [args1, args2]); // pass arguments as "Array"
Run Code Online (Sandbox Code Playgroud)
我们可以区分呼叫和应用方法如下
CALL:带有参数的函数单独提供.如果你知道要传递的参数或者没有传递参数,你可以使用call.
APPLY:使用作为数组提供的参数调用函数.如果您不知道有多少参数将传递给函数,则可以使用apply.
使用apply over call有一个优点,我们不需要更改参数的数量,只有我们可以更改传递的数组.
性能没有太大差异.但是我们可以说,与apply相比,调用有点快,因为数组需要在apply方法中进行求值.
这些方法之间的区别在于,您希望如何传递参数.
"A for array和C for comma"是一个方便的助记符.
调用和应用两者用于在this执行函数时强制该值.唯一的区别是call接受n+11是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');
Run Code Online (Sandbox Code Playgroud)
观察我们如何轻松地委派hello到sayHello使用apply,但是call这是很难实现的.
让我对此添加一些细节。
\n\n这两个调用几乎是等价的:
\n\nfunc.call(context, ...args); // pass an array as list with spread operator\n\nfunc.apply(context, args); // is same as using apply\nRun Code Online (Sandbox Code Playgroud)\n\n\xe2\x80\x99s 只有细微差别:
\n\n\n\n\n\n
\n- 运算
\nspread符 ... 允许将iterableargs作为列表传递以进行调用。- \n
apply仅接受类似数组的参数。
因此,这些调用是相辅相成的。在我们期望可迭代的地方,call工作,在我们期望类似数组的地方,apply工作。
对于可迭代和类似数组的对象(例如真正的数组),从技术上讲我们可以使用它们中的任何一个,但apply可能会更快,因为大多数 JavaScript 引擎在内部对其进行了更好的优化。
\n