首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么知道.call()和.apply()之间的区别如此重要?

为什么知道.call()和.apply()之间的区别如此重要?
EN

Stack Overflow用户
提问于 2015-09-06 04:28:42
回答 1查看 474关注 0票数 0

我一直在阅读一堆谈论JavaScript面试问题的网页,我注意到其中有很多人说,了解.call()和.apply()之间的区别很重要。

例如:

http://www.sitepoint.com/5-typical-javascript-interview-exercises/

https://github.com/h5bp/Front-end-Developer-Interview-Questions

对于我的生命来说,我不明白为什么这件事被认为如此重要。有人知道吗?对我来说,这可能和知道js长约会和js短约会之间的区别一样重要(也就是说,这对我来说似乎不太重要)。我的直觉告诉我,某个有影响力的人说,了解.call()和.apply()之间的区别至关重要,每个人都只是照搬了这个人说的话。但也许我误解了关于.call()和.apply()的一些东西?我没有把握。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-09-06 04:41:36

简单地说,更高级类型的Javascript偶尔需要使用.call().apply(),特别是试图代理函数、传递参数或控制this值的代码。

如果您正在做这些类型的事情,那么您必须知道.call().apply()是如何工作的,这样您就可以使用正确的方法(因为它们的工作方式不同)。如果您没有做这些高级的事情,那么很多Javascript都可以不用它们来编写。

作为一个面试问题,我认为这是一个合理的测试,您是否理解Javascript中一些更高级的参数传递、调用方法和this处理的细微差别。如果您想要在这些类型的问题上做得很好,那么您需要同时了解.call().apply(),现在您需要了解它们是做什么的,以及如何和何时使用它们,以及何时使用其中的一个问题。

this的整个概念以及它是如何在Javascript中被控制或设置的,对于经验较少的Javascript程序员(见鬼,我甚至见过一些经验丰富的开发人员不太了解它)通常不太了解,所以询问候选人与它相关的内容是一个合理的测试,而.call().apply()在某种程度上是这方面的核心。

如果您正在开发库或框架代码,您将更有可能在工作中使用.call().apply()

以下是一个基本的总结:

Javascript中的每个函数都是一个具有某些属性的对象。因此,除了能够调用像func()这样的函数之外,您还可以像func.length一样引用它上的属性。

每个函数所具有的两个属性是.call().apply()。它们都允许您以不同的方式调用函数,而不仅仅是将其称为func()

.call()

当然,我们都知道,如果您只想调用一个具有固定参数的函数,您可以只执行func(arg1, arg2),这些参数将传递给函数,但是如果您想要控制传递这些固定参数时this值是什么呢?将func作为func(arg1, arg2)调用将导致函数中的this值被设置为全局对象,即浏览器中的window,或者如果以严格模式运行,则设置为undefined。Javascript中的每个函数调用(如func(arg1, arg2) )都以这种方式重置this指针。这就是.call()进来的地方。你可以执行:

代码语言:javascript
复制
func.call(someThisValue, arg1, arg2)

它将执行与func(arg1, arg2)相同的操作,但它将导致将this指针设置为someThisValue

注意:您也可以只对一个参数使用.call(),它只会设置this指针而不传递任何参数。

代码语言:javascript
复制
func.call(someThisValue)

.apply()

但是,如果您的参数列表不是固定的,并且您的参数位于可变长度数组或类似数组的对象中,那么该怎么办?您不能真正使用.call(),因为您不能为每个可能的参数列表键入正确的.call()语句。这就是.apply()进来的地方。.apply()的一种规范用法是当您试图传递来自其他函数调用的参数时。当您代理其他函数调用以稍微修改它们的行为时,这种情况很常见,但是仍然调用原始函数和原始函数,或者有各种形式(所以您不知道传递的参数),或者很多不同类型的函数调用都是通过这个代理进行的。在这种情况下,您可以使用.apply(),通常与arguments对象一起使用。在.bind()中可以看到这方面的一个例子。

假设我想连接一些名为doIt()的现有函数,以便进行日志记录,而doIt()有许多不同的方法可以调用它。使用.apply(),我可以这样做:

代码语言:javascript
复制
// regular function already defined in your program
function doIt(arg1, arg2) {
    // do something
}

// then actual usage elsewhere in the program would be just this:
doIt("foo", "bar");

// now install a proxy that can intercept all calls to doIt() and
// add some behavior before and after
(function(origDoIt) {
     // replace doIt function with my own proxy
     doIt = function() {
         console.log("before doIt()");
         // call the original function with all the arguments and this pointer
         // that were passed
         var retVal = origDoIt.apply(this, arguments);
         console.log("after doIt()");
         return retVal;
     }
})(doIt);

还可以使用.apply()设置this指针,如下所示:

代码语言:javascript
复制
func.apply(someThisValue)

在这种特殊情况下(而且只有这种情况),它的工作原理与.call()相同。

以下是我最喜欢的.apply()用法之一。Math.max()方法接受可变数量的参数,它将返回这些参数中的最大数目。因此:

代码语言:javascript
复制
Math.max(1,2,3,4)

将返回4

但是,使用.apply(),我们可以在任何数组中找到最大数。

代码语言:javascript
复制
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max.apply(Math, list);
console.log(m);    // 1000

我们使用.apply()将整个list数组作为参数发送给Math.max(),因此它将对整个数组进行操作。

注意,当ES6在任何地方或在特定的执行环境中完全实现时,您还可以使用新的spread操作符来执行类似的操作:

代码语言:javascript
复制
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max(...list);
console.log(m);    // 1000

这成了我们用.apply()做的事情的简写

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32420074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档