手撕call、apply、bind

233 阅读2分钟

call实现

  • 语法

    func.call(thisArg, arg1, arg2)
    
  • 参数

    • thisArg 在func函数运行时的this值
    • arg1, arg2 指定的参数列表
  • 返回值

    • 使用指定的this值和参数调用函数的结果
  • 实现

    function.prototype.MyCall = function(ctx, ...argumnets) {
        // 1.获取this值
        ctx = ctx || window
        // 2.给this对象添加函数
        const _fn = Symbol('func')
        ctx._fn = this
        // 3.this对象调用函数并传入数据,获取返回结果
        const res = ctx._fn(...argumnets)
        // 4.删除函数
        delete ctx._fn
        // 5.返回结果
        return res
    }
    
    var name = 'zs'
    let obj = {
      name: 'ls'
    }
    function sayName(age) {
      console.info(`我叫${this.name},今年${age}`)
    }
    sayName(10) // 我叫zs,今年10
    sayName.myCall(obj, 20) // 我叫ls,今年20
    

apply实现

  • 语法

    func.call(thisArg, [argsArray])
    
  • 参数

    • thisArg 在func函数运行时的this值
    • argsArray 一个数组或类数组对象
  • 返回值

    • 使用指定的this值和参数调用函数的结果
  • 实现

    function.prototype.MyApply = function(ctx, argsArray) {
        // 1.获取this值
        ctx = ctx || window
        // 2.给this对象添加函数
        const _fn = Symbol('func')
        ctx._fn = this
        // 3.this对象调用函数并传入数据,获取返回结果
        // 第二个参数是数组,所以数据要展开传入
        const res = ctx._fn(...argsArray)
        // 4.删除函数
        delete ctx._fn
        // 5.返回结果
        return res
    }
    
    sayName.apply(obj, [19]) // 我叫zs,今年19  数据参数是一个个接收
    sayName.MyApply(obj, [20]) // 我叫ls,今年20
    

bind实现

  • 语法

    func.bind(thisArg[, arg1[, arg2[, ...]]])
    
  • 参数

    • thisArg 在func函数运行时的this值
    • arg1, arg2 一个数组或类数组对象
  • 返回值

    • 返回一个原函数的拷贝,并拥有指定的this值和初始参数
  • 实现

    function.prototype.MyBind = function(ctx, ...argsArray) {
        // 1.获取this值
        ctx = ctx || window
        // 2.给this对象添加函数
        const self = this
    
        // 3.定义返回函数
        const bund = function(...arguments) {
            // 判断直接使用,还是作为构造函数new实例
            let isNew = false
            try {
                isNew = this instanceof self
            } catch(err) {}
            // 直接使用继承ctx,构造函数继承bund函数的this
            return self.apply(isNew ? this: ctx, argsArray.concat(arguments))
        }
        
        // 4.原型继承
        cosnt Empty = new Function()
        Empty.prototype = this.prototype
        bund.prototype = new Empty()
        
        // 5.返回结果
        return bund
    }
    
    let obj2 = {
      name: 'test'
    }
    function speakName(age) {
      console.info(`我叫${this.name},今年${age}`)
    }
    let fn = speakName.MyBind(obj2, 99)
    fn()  // 我叫test,今年99
    let fn22 = new fn() // 我叫undefined,今年99