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

Rin*_*ngo 0 javascript

我一直在阅读一堆讨论JavaScript面试问题的网页,我注意到很多人都说知道.call()和.apply()之间的区别很重要.

例如:

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

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

对于我的生活,我无法理解为什么这被认为是如此重要.有人知道吗?对我而言,重要的是要知道js long date和js short date之间的区别(也就是说,这对我来说似乎并不重要).我的直觉告诉我某个有影响力的人说,了解.call()和.apply()之间的区别至关重要,而且每个人都只是复制了这个人说的话.但也许我误解了.call()和.apply()的一些事情?我不确定.

jfr*_*d00 5

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

如果你正在做这些类型的东西,那么你必须知道如何既.call().apply()工作,所以你可以用正确的方法(因为它们不相同的工作).如果你没有做那些类型的高级内容,那么可以在不使用它们的情况下编写大量的Javascript.

作为一个面试问题,我认为这是一个合理的测试,你是否理解了thisJavascript 中参数传递,调用方法和处理的一些更高级的细微差别.如果您想对这些类型的问题做好,你需要了解双方.call().apply(),现在该怎么解释他们所做的事情,以及如何和何时使用它们,当你将使用一个与其他.

this经验不足的Javascript程序员经常无法理解Javascript控制或设置的整个概念以及如何控制或设置(哎呀我甚至看到一些经验丰富的开发人员并不了解它)所以对与之相关的事情进行了问答.是一个合理的测试,.call()并且.apply()在某种程度上是中心.

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


这是一个基本的总结:

Javascript中的每个函数都是具有某些属性的对象.所以,除了能够调用类似的函数之外func(),你还可以像上面那样引用它们的属性func.length.

每个函数的两个属性是.call().apply().它们都允许您以与调用函数不同的方式调用函数func().

.呼叫()

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

func.call(someThisValue, arg1, arg2)
Run Code Online (Sandbox Code Playgroud)

并且它将执行相同的操作, func(arg1, arg2)除非它将this指针设置为someThisValue.

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

func.call(someThisValue)
Run Code Online (Sandbox Code Playgroud)

.应用()

但是,如果您的参数列表未修复且您的参数位于可变长度数组或类似数组的对象中,该怎么办?您无法真正使用,.call()因为您无法.call()为每个可能的参数列表键入正确的语句.这就是它的.apply()用武之地..apply()当你只是试图传递来自其他函数调用的参数时,规范使用.当您代理其他函数调用以稍微修改它们的行为时,这是很常见的,但仍然调用原始函数,并且原始文件具有各种形式(因此您不完全知道传递的参数)或许多不同类型的函数所有电话都通过这个代理.在这种情况下,您可以使用.apply(),通常与arguments对象一起使用.您可以在中查看此示例MDN polyfill for.bind().

假设我想挂钩一些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);
Run Code Online (Sandbox Code Playgroud)

仅供参考,.apply()也可用于将this指针设置为:

func.apply(someThisValue)
Run Code Online (Sandbox Code Playgroud)

在那种特殊情况下(只有那种情况),它的作用相同.call().


这是我最喜欢的用途之一.apply().该Math.max()方法接受可变数量的参数,它将返回任何这些参数的最大数量.从而:

Math.max(1,2,3,4)
Run Code Online (Sandbox Code Playgroud)

会回来的4.

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

var list = [999,888,777,666,555,444,333,1000];
var m = Math.max.apply(Math, list);
console.log(m);    // 1000
Run Code Online (Sandbox Code Playgroud)

我们.apply()用来发送整个list数组作为参数,Math.max()以便它可以在整个数组上运行.

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

var list = [999,888,777,666,555,444,333,1000];
var m = Math.max(...list);
console.log(m);    // 1000
Run Code Online (Sandbox Code Playgroud)

这成为我们正在做的事情的简写 .apply()