0%

手写call、apply、bind

本文主要介绍call、apply、bind三者的区别

博客1博客2

先尝试一下call的作用
1
2
3
4
5
6
7
8
const A = {
name: '中国人',
say(language) {
console.log(`${this.name} say ${language}`)
}
}

person.say('Chinese') // '中国人 say Chinese'

这时候B对象也想使用say方法,就可以用call来借用。

1
2
3
4
5
const B = {
name:'日本人',
}

A.say.call(B,'japanese') // '日本人 say japanese'

say里面的this.name本来应该是它自己的’中国人’,但是通过call的第一个参数指定了this改变指向的对象。使this指向了B,得到的’日本人’,除了第一个参数是指向的新对象之外,其后的都是原来say需要的参数。

call、apply、bind是干嘛的?有什么区别

这里直接引用大佬博客的原话了

call、apply 和 bind,都是用来改变函数的 this 指向的。
call、apply 和 bind 之间的区别比较大,前两者在改变 this 指向的同时,也会把目标函数给执行掉;后者则只负责改造 this,不作任何执行操作。
call 和 apply 之间的区别,则体现在对入参的要求上。前者只需要将目标函数的入参逐个传入即可,后者则希望入参以数组形式被传入。

实现call、apply、bind
  • call
    观察上文对call的使用,我们先自己写个叫myCall()的方法,然后拿到目标对象定义一个临时属性,把this指向他,最后返回这个临时属性的副本,就删除临时属性。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Function.prototype.myCall = function(target,...args){
    //拿到目标对象target,如果非真值就拿到window
    _target = target || window

    //通过Symbol函数生成Symbol值,防止属性名可能(基本不可能)产生冲突
    const symbolKey = Symbol()

    /*
    让目标对象的这个symbolKey属性被this指向
    因为调用的时候是xxx.say.myCall(),而this指向最后一个调用他的对象,
    所以这里this是xxx.say(),所以新的方法就是借用了say()
    ps:我的拙见,不知道对不对
    */
    _target[symbolKey] = this

    //用res接受借用后的函数,方便后续返回这个临时函数时,可以把他删除不占空间
    const res = _target[symbolKey](...args)
    delete _target[symbolKey]
    return res
    }
  • apply
    apply和call的差别在于携带参数。所以我们只要把myCall的参数的扩展运算符写法换成数组就可以
    1
    2
    3
    4
    5
    6
    7
    8
    Function.prototype.myApply = function(target,args){
    _target = target || window
    const symbolKey = Symbol()
    _target[symbolKey] = this
    const res = _target[symbolKey](...args)
    delete _target[symbolKey]
    return res
    }
  • bind
    相比上面两个,bind只需要改变this的指向,而不需要执行那个函数。所以我们需要返回一个函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Function.prototype.myBind = function(target,...outerArgs){
    // 处理边界条件
    let _target = target || {}
    const symbolKey = Symbol()
    _target[symbolKey] = this
    // 返回一个函数,innerArg也可以不带,写arguments
    return function F(...innerArgs) {
    if(_target[symbolKey] instanceof F){
    // new
    return new _target[symbolKey](...outerArgs,...innerArgs)
    }
    // 直接调用
    return _target[symbolKey].apply(target,[...outerArgs, ...innerArgs])
    }
    }