首先要明确的是这几个方法是Function.prototype上的,所以我们必定使用一个function来调用它。
call
基本语法是:
call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, /* …, */ argN)
也就是说必传的参数是this,其他则是用call的函数需要的其他参数。
以下面代码为例
const louie = {
name: 'Louie',
phoneBattery: 70,
charge: function(level) { // Louie拥有手机充电器,可以给自己的手机充电
this.phoneBattery = level
}
}
const alex = { // Alex没有手机充电器,他要充电需要借用Louie
name: 'Alex',
phoneBattery: 30
}
此时手机充电器还在Louie手里,于是Louie对Alex说“你把你的手机给我,我帮你充电”(call),也就是
louie.charge.call(alex, 100)
另一方面可以这样理解,调用call的函数相当于一个造型师,他call谁,可以改变谁的对应造型(状态)。
例如官方doc上例子做一个改造:
const stylist = {
change: function(clothing, shoes){ // 一个造型师的函数,它可以改变服饰和鞋子
// 当前情况下,这个造型师只能能改变自己的造型。
this.clothing = clothing
this.shoes = shoes
}
}
function Model(hairColor){ // 现在这里又出现了一个模特构造函数,它目前仅能进行发色改变
this.hairColor = hairColor
}
那么假设我们要实现让造型师的change函数能对model起作用,一种方法是:
const louie = new Model('blonde')
stylist.change.call(louie, 'T-shirt', 'runningShoes')
console.log(louie)
这种方法的问题是:对于每个model实例,我们都需要再调用一次call,所以不如把它直接放在构造函数中。
function Model(hairColor, clothing, shoes) {
stylist.change.call(this, clothing, shoes)
this.hairColor = hairColor
}
const louie = new Model('blonde', 'T-shirt', 'runningShoes')
console.log(louie)
apply
apply和call的区别不大,唯一的区别就是apply需要将this之外需要的参数作为一个数组来传递。
例如上面的例子可以改造成:
function Model(hairColor, clothing, shoes) {
stylist.change.apply(this, [clothing, shoes])
this.hairColor = hairColor
}
apply的一个用处是:可以直接传递数组来调用一些本不能直接传递数组的函数。 例如假设我们有一个数字数组,要找到它们的最大值,一种方法是我们可以将其展开,传入Math.max(), 还有一种方法是利用reduce,另外还可以使用apply。
const numbers = [2, 4, 1, 4, 2, 55]
// apply
let max = Math.max.apply(null, numbers)
console.log(max)
// spread syntax
let max2 = Math.max(...numbers)
console.log(max2)
// reduce
let max3 = numbers.reduce((a, b) => Math.max(a, b))
console.log(max3)
bind
还是以最上面的手机充电为例,我们前面相当于是充电器还在louie跟前,louie告诉alex说“你把你手机拿过来,我给你充”。
但是bind相当于是alex把手机充电器借走了,这样他之后想什么时候用,就什么时候用。
也就是说bind返回的是一个函数。
const alexCharge = louie.charge.bind(alex)
alexCharge(100) // 可以需要的时候再调用
从bind这个单词字面意思上也能看出,它的作用就是把一个this值绑定在它身上,毕竟默认情况下,如果我们在全局作用域像上面alexCharge(100)这样直接调用一个函数,this会是window。
结合使用
这里说实话不太理解,先写下来,以后回看。
官方文档上有一个例子是:
const slice = Array.prototype.slice
let res = slice.call([1, 2, 3])
上面等价于下面
const unboundSlice = Array.prototype.slice
const slice = Function.prototype.call.bind(unboundSlice)
slice([1,2,3])
目前能达到的理解是:利用Function.prototype.call.bind把call的执行上下文定为了unboundSlice,所以其实就相当于是:unboundSlice.call()。
但总感觉思路还是不清楚。
而且,比较好奇的是:下面这样又如何呢?不是更简单的一种封装吗?
function sliceParse(args) {
return slice.call(args)
}
总之本篇目前算是一个很基础的复习..还是要不断加强理解。