电话和申请有什么区别?

Joh*_*uff 3012 javascript performance function dynamic

使用callapply调用函数有什么区别?

var func = function() {
  alert('hello!');
};
Run Code Online (Sandbox Code Playgroud)

func.apply(); VS func.call();

上述两种方法之间是否存在性能差异?当它最好使用callapply,反之亦然?

fla*_*ine 3561

不同之处在于apply,您arguments可以使用数组调用函数; call要求明确列出参数.有用的助记是" 用于一个 rray和çÇ OMMA".

有关申请致电,请参阅MDN的文档.

伪语法:

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
Run Code Online (Sandbox Code Playgroud)

  • @KevinSchroeder:用javascript的说法,`[]`被称为**数组**,`{}`被称为**对象**. (312认同)
  • 我经常忘记哪个采用数组,并希望你列出参数.我曾经记得的一种技术是,如果方法的第一个字母以**a**开头,那么它需要一个数组即******pply数组 (89认同)
  • 要添加的一件事是args必须是数值数组([]).关联数组({})将不起作用. (24认同)
  • @SAM如果需要为函数调用更改_this_的值,则使用_call_而不是普通函数调用才有意义.一个例子(将函数arguments-object转换为数组):`Array.prototype.slice.call(arguments)`或`[] .slice.call(arguments)`.如果你在数组中有参数,_apply_是有意义的,例如在一个用(几乎)相同参数调用另一个函数的函数中.**建议**使用普通函数调用`funcname(arg1)`如果你做了你需要的东西,并在你真正需要的时候保存_call_和_apply_用于那些特殊场合. (16认同)
  • @KunalSingh`call`和`apply`都有两个参数.`apply'和`call`函数的第一个参数必须是所有者对象,第二个参数分别是数组或逗号分隔参数.如果你传递`null`或`undefined`作为第一个参数,那么在非严格模式下它们被全局对象替换,即`window` (4认同)
  • 单独的助记符值得回答.我不认为我需要再查一次! (3认同)
  • @AJQarshi @KunalSingh只是为了阐述Qarshi的答案,第一个参数,所有者对象,就像他所说的那样,是你想要传递给函数的执行上下文(`this` context).当一个对象作为参数传递时,调用的函数绑定到对象的执行上下文,对函数中成员的任何引用都将指向现有的对象成员.希望这是有道理的. (2认同)

not*_*oop 222

K. 斯科特艾伦在这件事上写得很好.

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

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

所以:

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

  • apply()和call()的第二个参数是可选的,不是必需的. (42认同)
  • 第一个参数也不需要. (34认同)
  • @Ikrom,“call”不需要第一个参数,但“apply”需要第一个参数 (2认同)

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的参数的个数.

  • 那里有用的助记符!我将更改"一个或两个参数"以表示"最多两个参数",因为"apply"的第一个或第二个参数都不是必需的.我不确定为什么一个人会在没有参数的情况下调用`apply`或`call`.看起来有人试图找出原因http://stackoverflow.com/questions/15903782/call-apply-with-no-parameters-vs-simply-calling-a-function-with-paran (2认同)

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...)

  • 有趣的是,即使没有阵列,呼叫仍然要快得多.http://jsperf.com/applyvscallvsfn2 (12认同)

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永远不能nullundefined当一个函数被调用.当nullundefined作为接收器提供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的工作方式如下:

  1. 绑定返回可以执行的函数的实例
  2. 第一个参数是' this '
  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
*/
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值的函数和作为数组(或类数组对象)提供的参数.

句法

fun.apply(thisArg, [argsArray])
Run Code Online (Sandbox Code Playgroud)

Function.prototype.call()上的MDN文档:

call()方法调用具有给定this值的函数和单独提供的参数.

句法

fun.call(thisArg[, arg1[, arg2[, ...]]])
Run Code Online (Sandbox Code Playgroud)

来自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)

另见这个小提琴.


Rak*_*mar 11

根本区别在于call()接受参数列表,同时apply()接受单个参数数组.


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)


Wil*_*een 8

概括:

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
Run 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 logged
Run Code Online (Sandbox Code Playgroud)


San*_*ath 7

区别在于call()单独获取函数参数,并apply()在数组中获取函数参数.


Ali*_*eza 7

主要区别是,使用 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)


abd*_* kk 7

我只是想在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)


Pra*_*n D 6

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

CALL:带有参数的函数单独提供.如果你知道要传递的参数或者没有传递参数,你可以使用call.

APPLY:使用作为数组提供的参数调用函数.如果您不知道有多少参数将传递给函数,则可以使用apply.

使用apply over call有一个优点,我们不需要更改参数的数量,只有我们可以更改传递的数组.

性能没有太大差异.但是我们可以说,与apply相比,调用有点快,因为数组需要在apply方法中进行求值.


ven*_*668 5

这些方法之间的区别在于,您希望如何传递参数.

"A for array和C for comma"是一个方便的助记符.

  • 这个答案提供的内容在其他答案中还没有很好地提供? (10认同)

Rag*_*dra 5

调用和应用两者用于在this执行函数时强制该值.唯一的区别是call接受n+11是this和的参数'n' arguments.apply只需要两个参数,一个是this另一个是参数数组.

优点我看到applycall的是,我们可以轻松地委派一个函数调用来毫不费力等功能;

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)

观察我们如何轻松地委派hellosayHello使用apply,但是call这是很难实现的.


Pra*_*iya 5

让我对此添加一些细节。

\n\n

这两个调用几乎是等价的:

\n\n
func.call(context, ...args); // pass an array as list with spread operator\n\nfunc.apply(context, args);   // is same as using apply\n
Run Code Online (Sandbox Code Playgroud)\n\n

\xe2\x80\x99s 只有细微差别:

\n\n
\n
    \n
  • 运算spread符 ... 允许将iterable args作为列表传递以进行调用。
  • \n
  • apply仅接受类似数组的参数。
  • \n
\n
\n\n

因此,这些调用是相辅相成的。在我们期望可迭代的地方,call工作,在我们期望类似数组的地方,apply工作。

\n\n

对于可迭代类似数组的对象(例如真正的数组),从技术上讲我们可以使用它们中的任何一个,但apply可能会更快,因为大多数 JavaScript 引擎在内部对其进行了更好的优化。

\n