JS原生实现bind、call、apply的方法整理

蛰伏已久 蛰伏已久 2019-10-25

bind的原生实现

我们先来实现bind,实现每个功能之前,肯定要先看下他们的api,到底是怎么调用的,知道怎么调用才能实现。

bind除了可用来绑定this外,还可以绑定默认的参数,如下示例。

function test(arg1,arg2) {
    console.log(this.a )
    console.log(arg1)
    console.log(arg2)
}

let obj = {
    a:'a'
}
test.bind(obj,'b')('c')  
//a
//b
//c

通过观察我们发现就可以找到实现的思路:

  • 每个函数都可以调用bind,所以肯定要把bind方法放到Function.protorype上

  • bind返回的是个函数

  • bind可以接收默认参数,我们要保持这个默认参数,然后再返回的函数将默认参数和后传参数合并

  • 可以基于函数的apply功能来更改this并接收合并后参数

function test(arg1,arg2) {
    console.log(this.a )
    console.log(arg1)
    console.log(arg2)
}

let obj = {
    a:'a'
}


Function.prototype.myBind = function (context) {
    const self = this
    const args = [...arguments].slice(1) //接收除context之外的参数,也就是绑定的默认参数
    return function () {
        let all_args = args.concat([...arguments])  //将默认参数和调用参数合并
        let result =  self.apply(context,all_args)  //借助apply来执行
        return result
    }
}

test.myBind(obj,'b')('c')
//a
//b
//c

call和apply的实现

上面我们基于apply实现了bind方法,现在再原生实现apply,同样的我们看看怎么使用apply。

apply接收的第一个参数为要替换this的对象,第二个参数是个数组

function test(arg1,arg2) {
    console.log(this.a )
    console.log(arg1)
    console.log(arg2)
}

let obj = {
    a:'a'
}


test.apply(obj,['b','c'])

我们先来分析一下:

  • 首先肯定是要给 Function.prototype添加一个apply方法

  • apply接收两个参数,第一个是上下文,第二个是个数组

  • apply是立即执行的,不像bind返回个函数

  • 重点是怎么修改this呢,这个可以借助this相关的知识点:谁调用某个函数,函数中的this就指向谁

Function.prototype.myApply = function (context = window,args=[]) {
    const self = this
    context.fn = self  //给上下文添加一个fn属性指向调用myApply的函数,后续执行context.fn(),则fn中的this就指向了context,达到替换this的目的
    let result = context.fn(...args)
    delete context.fn  //得到结果之后记得再把fn从context中删除,要不就导致context变化了,这不符合apply的功能
    return result
}

类似的,我们也可以实现call的功能,call和apply的区别就是传的参数不同,可以用...args来接收call中的其他参数,后面实现就和apply相同了

Function.prototype.myCall = function (context = window,...args) {
    const self = this
    context.fn = self
    let result = context.fn(...args)
    delete context.fn
    return result
}


分享到

点赞(1)