数年前在四处求职面试时,时常遇到面试官询问 Javascript 中 Function 的 apply
、 bind
、 call
差异是什么,但当时的我仅一知半解,回答得支支呜呜;前阵子开始练习刷 CodeWars 的题目,便时常遇到这些函数的应用,也有了机会重新深入理解这三者的差异。
apply
、 bind
、 call
是什么?Javascript 中万物皆对象,除了数种基本类型之外,其他常用的 Function
、 Array
、 Date
等等,其实都是 Runtime 中默认的 Object
,Runtime 会建立好个别默认的 prototype
,并在对象实例产生时,把 __proto__
指到个别的 prototype
,使对象实例可以使用 prototype
中定义好的属性、函数;这也就是常听到的原型链。
例如:
let arr = new Array()
arr.__proto__ === Array.prototype // true
而这篇文章要讨论的 apply
、 bind
、 call
,则是 Function.prototype
中的三个函数,因为他们有些相似,因此时常被拿来一起讨论、比较。
首先来看看可能比较多人使用过的 bind
。
大家可能对绑 this
比较熟悉,例如:
var name = 'foo'
function logName(){
console.log(this.name)
}
var tmp = {
name: 'bar'
}
var newFunction = logName.bind(tmp)
通过 bind()
,借用已建立的函数来创造新的函数,但将 this
绑到指定的对象上。
比较少使用到的是, bind
还可以绑定传入函数的参数。例如:
function sum(a,b) {
return a + b
}
let plusTwo = sum.bind(this, 2)
let plusFive = sum.bind(this, 5)
使用 bind
方法可以提前设定函数的某些参数,这样一来,当你需要多次使用同一个函数但参数略有不同的时候,就可以创建多个版本的函数,每个版本都固定了不同的参数。这样做不仅提高了代码的复用性,也使得函数的使用变得更加灵活和方便。
总结一下, bind()
接受的第一位参数为指定的 this
,其余参数则依序传给被绑定的函数,作为固定的参数,最后会返回一个新的函数。
接着来看 apply
跟 call
,因为两者的行为几乎一模一样,仅接受的参数类型不同,这边就一起说明。 不啰嗦,直接看个例子:
let str = '12345'
Array.prototype.map.apply(str, [c => c ** 2])
// [1, 4, 9, 16, 25 ]
Array.prototype.map.call(str, c => c ** 3)
// [1, 8, 27, 64, 125 ]
str.map(c => c ** 2)
// TypeError: str.map is not a function
apply
跟 call
,可以想像成跟别的对象借用函数。第一参数同样为 this
,其余参数则为传入函数中的参数。例如前例中跟 Array.prototype
借用 str
自己无法呼叫的 map
函数。
而 apply
与 call
唯一的差别,就是 apply
接受的要传入函数参数为数组, call
则为逐项传入。
再看一个简单的例子:
function sum (...argu) {
return argu.reduce((acc, c) => +c === c ? acc + c : acc)
}
let params = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
sum.apply(null, params) // 55
sum.call(null, ...params) // 55
ES6 开始有了展开运算符, call
跟 apply
在使用时差异几乎可以忽略不计了。不过网络上有些讨论说 call
的性能略优于 apply
,笔者没有实际测试,大家可以实践测试看看。
以上就是这次关于 apply、bind、call 的心得分享,熟悉之后灵活运用在项目中吧!如果文中有任何不清楚或错误的地方,也都欢迎你不吝告知!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。