简单说,apply 是给框架设计者用的,而 call 是给开发者用的。两者都能扩充函数作用域。而 bind,主要是绑定作用域,并不是函数执行。
apply 方法调用一个具有给定 this 值的函数,以及作为一个数组,或类似数组对象提供的参数。call 方法的作用和 apply 方法类似,区别就是 call 方法接受的是参数列表,而 apply 方法接受的是一个参数数组。
apply 语法:
func.apply(thisArg, [argsArray])
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
call 语法:
function.call(thisArg, arg1, arg2, ...)
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
bind 语法:
function.bind(thisArg[, arg1[, arg2[, ...]]])
从调用语法上看,bind 语法与 call 类似。
对一些函数的调用,例如 Math.max,利用 apply,可以将不定参数的调试方式,转化为参数数组进行传递。前面我们讲,apply 是给框架设计者使用,而 call 是给开发者使用的,主要是指 apply 传递的是数组,而 call 传递的是不定参数。
其实在开发中,无论是写框架,还是写业务,记住 apply 这一个方法就足够了。
上面我们看到 apply 方法的第二个参数,可以是一个类数组对象。什么是类数组对象?
每个 Function 的作用域中,都有一个 arguments 对象,这个对象就是一个类数组对象。它是一个对象,但具有 length 属性,并且键值对严格按照零始的数字递增,所以是一个类数组对象。
关于类数组对象,使用 Arrry.prototype.slice.apply(arguments),可以将类数组对象,转换为一个纯正的数组。在 Console 面板中,我们可以直接这样声明对象的方式,创建一个类数组:
let arr1 = {length:2,0:'a',1:'b'}, arr2 = ['a','b']
Array.prototype.slice.apply(arr1)
对我们开讲,记住使用 apply 就可以,将 call 忘记吧。call 只是给开发者小白的一个语法糖。事实上不定参数只在第一层调用时方便,后续调用就不方便了。
这篇小内容虽然简单,但我觉得与生活结合得并不好。可能看了之后,并不容易记住,过一段时间可能还会忘记。尝试举一个生活中的例子吧。
假如我们想让某个人 B,去做一件事。但于由于种种原因吧,我们并不能与 B 直接进行沟通,可能因为语言不通或其它原因,这个我们不管。
现在为了完成目标,我们请 A 做为中间人,A 可以同时与我们、与 B 打交道。
如果我们让 A,去把 B 叫过来,一句一句安排,由 A 一句一句翻译,让 B 执行,这相当于是 call 的调用方法。
但是这样不高效,我们这个线程会被阻塞。现在我们为了提高工作效率,我们不让 B 过来了,我们直接把任务安排给 A,一句一句的任务,仿佛打包成了一个数组,一起给 A,然后让 A 去直接找 B,让 B 执行。这样一来,我们可以先后派出 A1、A2、A3 等,可以同时执行 N 多事件。工作效率是提高了。这就相当于是 apply 的调用方式。
至于 bind 这种方式,是我们把 B 叫过来,一句一句安排,同时由 A 翻译好,但是不让 B 马上执行,也不让 B 离开,直到某个时间点,我们一声令下,B 开始干活。这种情况相当于 B 是我们的贴身保镖。
例子可能不贴切,欢迎留言讨论。
2020 年 6 月 17 日
---
如果还有疑问与时间,可以看一下这几篇文章:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
https://zhuanlan.zhihu.com/p/47052231
https://blog.csdn.net/qq_27626333/article/details/51831282