call 和 apply 和有什么不一样?

问:

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

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

func.apply(); 与 func.call();

上述两种方法之间是否存在性能差异?什么时候最好使用 call 而不是 apply,反之亦然?

答1:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

不同之处在于 apply 允许您使用 arguments 作为数组调用函数; call 要求明确列出参数。一个有用的助记符是 “A 表示 a 射线,C 表示 comma。”

请参阅 MDN 关于 apply 和 call 的文档。

伪语法:

theFunction.apply(valueForThis, arrayOfArgs)

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

从 ES6 开始,还可以使用 spread 数组与 call 函数一起使用,您可以看到兼容性 here。

示例代码:

function theFunction(name,professional) { console.log(“我叫”+name+“,我是”+professional+“。”); } theFunction(“约翰”, “消防员”); theFunction.apply(undefined, [“Susan”, “学校老师”]); theFunction.call(undefined, “克劳德”, “数学家”); theFunction.call(undefined, …[“Matthew”, “physicist”]); // 与扩展运算符一起使用

要添加的一件事是 args 必须是数字数组 ([])。关联数组 ({}) 将不起作用。

@KevinSchroeder:在 javascript 中,[] 被称为 array,{} 被称为 object。

我经常忘记哪个需要一个数组,哪个需要你列出参数。我曾经记得的一个技巧是,如果方法的第一个字母以 a 开头,那么它需要一个数组,即一个应用数组

@SAM 使用 call 而不是普通的函数调用只有在您需要更改函数调用的 this 值时才有意义。一个示例(将函数参数对象转换为数组):Array.prototype.slice.call(arguments) 或 [].slice.call(arguments)。 apply 如果您在数组中有参数,例如在调用具有(几乎)相同参数的另一个函数的函数中,则 apply 是有意义的。 建议 如果可以满足您的需要,请使用普通函数调用 funcname(arg1),并在您真正需要的特殊场合保存 call 和 apply他们。

@KunalSingh call 和 apply 都有两个参数。 apply' and call 函数的第一个参数必须是所有者对象,第二个参数将分别是数组或逗号分隔的参数。如果您将 null 或 undefined 作为第一个参数传递,那么在非严格模式下,它们将被替换为全局对象,即 window

答2:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

K. Scott Allen 对此有 a nice writeup。

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

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

所以:

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

apply() 和 call() 的第二个参数是可选的,不是必需的。

第一个参数也不是必需的。

@Ikrom,第一个参数不是 call 所必需的,而是 apply 所必需的

答3:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

要回答有关何时使用每个函数的部分,如果您不知道要传递的参数数量,或者如果它们已经在数组或类似数组的对象中(如 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))。我没有测试过它,所以可能会有差异,但它会非常特定于浏览器。如果您还没有数组中的参数,call 可能会更快,如果有的话,apply 可能会更快。

答4:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

这是一个很好的助记符。 Apply 使用数组并且总是使用一两个参数。当您使用 Call 时,您必须计算参数的数量。

有用的助记符就在那里!我会将“一个或两个参数”更改为“最多两个参数”,因为 apply 的第一个或第二个参数都不是必需的。我不确定为什么会在没有参数的情况下调用 apply 或 call。似乎有人试图找出这里的原因stackoverflow.com/questions/15903782/…

答5:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

虽然这是一个老话题,但我只想指出 .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…)

这取决于函数对参数/数组的作用,如果不需要处理数组,是否需要更少的时间?

有趣的是,即使没有数组,调用仍然要快得多。 jsperf.com/applyvscallvsfn2

@JoshMc 那将是非常特定于浏览器的。在 IE 11 中,我的应用速度是通话速度的两倍。

1. 创建一个新数组意味着垃圾收集器需要在某个时候清理它。 2. 使用解引用访问数组中的项目比直接访问变量(参数)效率低。 (我相信这就是 kmatheny 所说的“解析”,这实际上是完全不同的东西。)但是我的论点都没有解释 jsperf。这必须与引擎对这两个函数的实现有关,例如,如果没有传递,它们可能会创建一个空数组。

感谢您分享测试和视频

答6:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

遵循 Closure: The Definitive Guide by 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”中所述,当 JavaScript 在 Web 浏览器中执行时,window 是全局对象。这导致了一些令人惊讶的行为:

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 的属性的不良副作用。

将函数视为不知道分配给它的变量可能会有所帮助。这有助于强化这样的想法,即 this 的值将在调用函数时而不是在定义函数时绑定。

提取结束。

请注意,additionalValues 未在 obj.addValues 正文中引用

我知道你在回答这个问题,但想补充一点:你可以在定义 f 时使用 bind。 var f = obj.addValues; 变为 var f = obj.addValues.bind(obj),现在 f(20) 无需每次都使用 call 或 apply 即可工作。

我知道这不是你写的,但你确实强调了书中相关的文字和示例,我非常感激。他们非常有帮助。

答7:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

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

一个小代码示例:

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的人请查看:What is console.log and how do I use it?

答8:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

调用、应用和绑定的另一个例子。 Call 和 Apply 之间的区别很明显,但 Bind 的工作方式如下:

Bind 返回一个可以执行的函数实例 第一个参数是 ‘this’ 第二个参数是逗号分隔的参数列表(如调用)

}

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
*/

答9:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

我想展示一个示例,其中使用了“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

答10:

huntsbot.com全球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/

// call() === 逗号分隔的参数 (arguments-list) .call(this, args1, args2, args3, ...) // apply() === 参数数组 (array-items) .应用(这个,[arr0,arr1,arr2,...])

答11:

huntsbot.com – 高效赚钱,自由工作

从 the MDN docs on Function.prototype.apply() :

apply() 方法使用给定的 this 值和作为数组(或类似数组的对象)提供的参数调用函数。语法 fun.apply(thisArg, [argsArray])

从 the MDN docs on Function.prototype.call() :

call() 方法使用给定的 this 值和单独提供的参数调用函数。语法 fun.call(thisArg[, arg1[, arg2[, …]]])

从 Function.apply and Function.call in JavaScript :

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

代码示例:

var doSomething = function() { var arr = []; for(i in arguments) { if(typeof this[arguments[i]] !== ‘undefined’) { arr.push(this[arguments[i]]); } } 返回 arr; } var output = function(position, obj) { document.body.innerHTML += 'output ’ + position + ‘’ + JSON.stringify(obj) + ‘\n\n< br><小时>’; } 输出(1,doSomething(“一”,“二”,“二”,“一”));输出(2,doSomething.apply({一:‘史蒂文’,二:‘简’},[‘一’,‘二’,‘二’,‘一’]));输出(3,doSomething.call({一个:‘史蒂文’,两个:‘简’},‘一个’,‘两个’,‘两个’,‘一个’));

另见this Fiddle。

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

原文链接:https://www.huntsbot.com/qa/yOnr/what-is-the-difference-between-call-and-apply?lang=zh_CN&from=csdn

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值