手写call,bind,apply

315 阅读1分钟

手写call,apply,bind


    Function.prototype._call = function (ctx, ...args) {
        const fn = Symbol('fn')  // 声明一个独有的symbol属性(防止覆盖其他变量)
        console.log('...', ...args) // a,b
        console.log('args', args) // [a,b]
        // let arg = Array.from(args) // 这里不用转化了,因为args 本身就是数组
        // console.log('arg', arg)
        let context = ctx || window // 若没有this传入,默认绑定window对象
        context.fn = this // 函数赋值,改变this指向
        let result = args.length > 0 ? context.fn(...args) : context.fn() // 执行当前函数,并且判断有无参数
        delete context.fn // 删除我们改写的fn属性,因为我们只是要借用this,不能改变对象,执行完就删除
        return result // 返回结果
    }
    Function.prototype._apply = function (ctx, args = []) {
        const fn = Symbol('fn')
        if (!(args && args instanceof Array)) {
            throw ('请传入数组')
        }
        let context = ctx || window
        context.fn = this
        let result = args.length > 0 ? context.fn(...args) : context.fn()
        delete context.fn
        return result

    }
    Function.prototype._bind = function (ctx, ...args) {
        let that = this
        return function () {
            return that._call(ctx, ...args)
        }
    }
    var name = "1";
    var obj = {
        name: 2,
        prop: {
            name: 3,
            getName: function (age, s) {
                return {
                    name: this.name,
                    age: age,
                    s: s
                }
            }
        }
    }
    console.info(obj.prop.getName(3, 4)); // 3, 3, 4
    console.info(obj.prop.getName.call(obj, 3, 4)); //2, 3, 4 
    console.info('_call实现', obj.prop.getName._call(this, 3, 4)); //this是window 1, 3, 4
    console.info('_apply实现', obj.prop.getName._apply(this, [2, 3])); //this是window 1, 2, 3
    let bindHandle = obj.prop.getName._bind(this, 2, 3)
    console.log('bindHandle()', bindHandle())//this是window 1, 2, 3

后续文章输出

  1. 在手写bind中,其实也有闭包的引用,下一文就讲讲闭包