js基础复习-call、apply、bind

204 阅读3分钟

首先要明确的是这几个方法是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)
}

总之本篇目前算是一个很基础的复习..还是要不断加强理解。