Javascript 为什么知道.call()和.apply()之间的区别如此重要?
我一直在阅读一些关于JavaScript面试问题的网页,我注意到很多网页都说了解.call()和.apply()之间的区别很重要 例如:Javascript 为什么知道.call()和.apply()之间的区别如此重要?,javascript,Javascript,我一直在阅读一些关于JavaScript面试问题的网页,我注意到很多网页都说了解.call()和.apply()之间的区别很重要 例如: 就我的一生而言,我无法理解为什么这被认为如此重要。有人知道吗?对我来说,这可能和知道js长日期和js短日期之间的区别一样重要(也就是说,这对我来说似乎并不重要)。我的直觉告诉我,某个有影响力的人在某个时候说,知道.call()和.apply()之间的区别是至关重要的,每个人都只是照搬了这个人的话。但也许我误解了关于.call()和.apply()的某些内容
就我的一生而言,我无法理解为什么这被认为如此重要。有人知道吗?对我来说,这可能和知道js长日期和js短日期之间的区别一样重要(也就是说,这对我来说似乎并不重要)。我的直觉告诉我,某个有影响力的人在某个时候说,知道.call()和.apply()之间的区别是至关重要的,每个人都只是照搬了这个人的话。但也许我误解了关于.call()和.apply()的某些内容?我不确定。简单地说,更高级的Javascript类型偶尔需要使用
.call()
或.apply()
,尤其是尝试代理函数和传递参数或控制this
值的代码
如果你在做这些事情,那么你必须知道.call()
和.apply()
是如何工作的,这样你才能使用正确的方法(因为它们的工作方式不同)。如果您没有做这些类型的高级工作,那么很多Javascript都可以不用它们来编写
作为一个面试问题,我认为这是一个合理的测试,测试你是否理解Javascript中参数传递、调用方法和这个处理的一些更高级的细微差别。如果你想在这些类型的问题上做得很好,你需要了解.call()
和.apply()
,现在如何解释它们的作用,以及如何和何时使用它们,以及何时使用它们
这个
的整个概念以及它是如何在Javascript中控制或设置的,经验较少的Javascript程序员往往不太了解(见鬼,我甚至看到一些经验丰富的开发人员不太了解它),因此对候选人进行与此相关的测试是合理的,.call()
和.apply()
在某种程度上是这方面的核心
如果您正在开发库或框架代码,那么您在工作中更可能使用.call()
或.apply()
以下是一个基本总结:
Javascript中的每个函数都是具有某些属性的对象。因此,除了能够调用像func()
这样的函数外,还可以引用它的属性,比如func.length
每个函数的两个属性是.call()
和.apply()
。它们都允许您以不同的方式调用函数,而不仅仅是将其作为func()
调用
.call()
当然,我们都知道,如果您只想使用固定数量的参数调用函数,那么您可以只执行func(arg1,arg2)
,这些参数将被传递给函数,但是如果您想控制传递这些固定参数时这个
值将是什么呢?将func调用为func(arg1,arg2)
将导致该函数中的此
值设置为浏览器中的窗口中的全局对象,或者在严格模式下运行时设置为未定义
。Javascript中的每个函数调用,例如func(arg1,arg2)
都会以这种方式重置this
指针。这就是.call()
的用武之地。您可以执行:
func.call(someThisValue, arg1, arg2)
它将执行与func(arg1,arg2)
相同的操作,只是它将导致this
指针设置为someThisValue
注意:您也可以只使用一个参数来使用.call()
,它将只设置这个
指针,而不传递任何参数
func.call(someThisValue)
.apply()
但是,如果参数列表不是固定的,并且参数位于可变长度数组或类似数组的对象中,该怎么办。您不能真正使用.call()
,因为您不能为每个可能的参数列表键入正确的.call()
语句。这就是.apply()
的用武之地。.apply()
的一个规范用法是当您试图传递来自其他函数调用的参数时。当您代理其他函数调用以稍微修改它们的行为,但仍然调用原始函数时,这是很常见的,原始函数或者具有各种形式(因此您不确切知道传递的参数),或者许多不同类型的函数调用都通过此代理。在这种情况下,您可以使用.apply()
,通常与参数
对象一起使用。您可以在中看到这方面的示例
假设我想挂接一些名为doIt()
的现有函数用于日志记录,并且doIt()
有许多不同的方法可以调用它。使用.apply()
,我可以这样做:
// 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()
也可用于设置此
指针,如下所示:
func.apply(someThisValue)
在该特定情况下(仅在该情况下),它的工作原理与.call()
相同
下面是我最喜欢的.apply()
用法之一。Math.max()。因此:
Math.max(1,2,3,4)
将返回4
但是,使用.apply()
,我们可以在任何数组中找到最大数
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max.apply(Math, list);
console.log(m); // 1000
我们使用.apply()
将整个列表
数组作为参数发送到Math.max()
,因此它将在整个数组上运行
注意,当ES6在任何地方或在特定的执行环境中完全实现时,您也可以使用新的spread操作符来执行类似的操作
var list = [999,888,777,666,555,444,333,1000];
var m = Math.max(...list);
console.log(m); // 1000