让前端飞

JavaScript手写call、bind、apply

2020-10-30  本文已影响0人  阿毛啊726

三个都是用来改变this指向的
三者传入的第一个参数都为对象,其余参数
1,call 参数是一个一个传进去的
2,apply 参数是用数组传进去的,
3,bind 是一个方法,后面加 ( ) 以外和两者没区别,参数可以一个一个传,也可以数组传

obj.myFun.call(db,'成都','上海');  // 德玛 年龄 99  来自 成都去往上海
obj.myFun.apply(db,['成都','上海']);      // 德玛 年龄 99  来自 成都去往上海  
obj.myFun.bind(db,'成都','上海')();       // 德玛 年龄 99  来自 成都去往上海
obj.myFun.bind(db,['成都','上海'])();   // 德玛 年龄 99  来自 成都, 上海去往 undefined

手写实现call apply bind
1)判断this是不是函数
2)确定执行上下文为context还是window
3)将context.fn作为this,
4)获取函数的传参,从第二个参数开始取,因为bind,call,apply的第一个传参为this改变后的对象
5)执行该函数,因为已经将this指定给了context.fn所以执行的context.fn
6)清除context.fn新设定的属性
7)返回result
call

Function.prototype.myCall = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    //如果没有传入this,绑定Windows
    context = context || window
    //改变this的指向
    context.fn = this
    //获取参数,从arguments的第二个参数开始取,因为第一个参数为对象
    const args = [...arguments].slice(1)
    //执行当前函数
    const result = context.fn(...args)
    //删除我们声明的fn属性
    delete context.fn
    return result
}

apply

Function.prototype.myApply = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    context = context || window
    context.fn = this
    let result
    // 处理参数和 call 有区别 如果有第二个数组的传参,把参数传进去
    if (arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

bind

Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    const _this = this
    const args = [...arguments].slice(1)
    // 返回⼀个函数
    return function F() {
        // 因为返回了⼀个函数,我们可以 new F(),所以需要判断
        if (this instanceof F) {
            return new _this(...args, ...arguments) 
        }
        return _this.apply(context, args.concat(...arguments))
    } 
}
上一篇 下一篇

猜你喜欢

热点阅读