手写源码之Js中的 call() apply() bind()

说多无益, 直接上代码, 肯定还有一些不完善的地方, 我参考了一下
原生js源码之JavaScript的call方法,自己来实现

call()
'use strict'

var person = {
  name: "Tom",
  sayHi(a, b) {
    // console.log('a', a)
    // console.log('b', b)
    // return this.name + " 在向你问好!" + a + b
    return this.name + " 在向你问好!" + a.name + b.name;
  }
}

var pig = {
  name: 'Jerry'
}

/**
 * 只处理了 参数为 string, number, object 的情况
 * @returns any
 */
Function.prototype.myCall = function() {
  if (arguments.length === 0) {
    return this()
  } else {
    // 第一个参数作为上下文
    let context = arguments[0]
    // 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的
    if (context === null || context === undefined) return this()
    if (typeof context !== 'object') context = {}
    // this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法
    context[this.name] = this

    let func = this.name + '('
    let arg
    let myArgs = []
    for (let i = 1; i < arguments.length; i++) {
      arg = arguments[i]
      console.log('arg', arg)
      if (typeof arg === 'string') {
        if (i === 1) {
          func += `'${arg}'`
        } else {
          func += `,'${arg}'`
        }
      } else if (typeof arg === 'number') {
        if (i === 1) {
          func += arg
        } else {
          func += "," + arg
        }
      } else if (typeof arg === 'object') {
        myArgs.push(arg)
        if (i === 1) {
          func += `myArgs[${i - 1}]`
        } else {
          func += `,myArgs[${i - 1}]`
        }
      }
    }
    func += ')'
    console.dir(func)
    // 拿到执行后的结果
    const result = eval('context.'+ func)
    // 删除新增的属性
    delete context[this.name]
    // 返回执行后的结果
    return result
  }
}

// console.log(person.sayHi.myCall(pig, 1, 2))
console.log(person.sayHi.myCall(pig, { name: 'c' }, { name: 'd' }))
console.log(pig)
apply()

其实和 call() 没区别, 只是换了一下参数传入的形式

'use strict'

var person = {
  name: "Tom",
  sayHi(a, b) {
    // console.log('a', a)
    // console.log('b', b)
    return this.name + " 在向你问好!" + a + b
    // return this.name + " 在向你问好!" + a.name + b.name;
  }
}

var pig = {
  name: 'Jerry'
}

/**
 * 只处理了 参数为 string, number, object 的情况
 * @returns any
 */
Function.prototype.myApply = function() {
  if (arguments.length === 0) {
    return this()
  } else {
    // 第一个参数作为上下文
    let context = arguments[0]
    // 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的
    if (context === null || context === undefined) return this()
    if (typeof context !== 'object') context = {}
    // this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法
    context[this.name] = this

    let func = this.name + '('
    let arg
    let myArgs = []
    for (let i = 0; i < arguments.length; i++) {
      arg = arguments[1][i]
      console.log('arg', arg)
      if (typeof arg === 'string') {
        if (i === 0) {
          func += `'${arg}'`
        } else {
          func += `,'${arg}'`
        }
      } else if (typeof arg === 'number') {
        if (i === 0) {
          func += arg
        } else {
          func += "," + arg
        }
      } else if (typeof arg === 'object') {
        myArgs.push(arg)
        if (i === 0) {
          func += `myArgs[${i}]`
        } else {
          func += `,myArgs[${i}]`
        }
      }
    }
    func += ')'
    console.dir(func)
    // 拿到执行后的结果
    const result = eval('context.'+ func)
    // 删除新增的属性
    delete context[this.name]
    // 返回执行后的结果
    return result
  }
}

console.log(person.sayHi.myApply(pig, [1, 2]))
// console.log(person.sayHi.myApply(pig, [{ name: 'c' }, { name: 'd' }]))
console.log(pig)

bind()

只是需要返回一个函数了

'use strict'

var person = {
  name: "Tom",
  sayHi(a, b) {
    // console.log('a', a)
    // console.log('b', b)
    // return this.name + " 在向你问好!" + a + b
    return this.name + " 在向你问好!" + a.name + b.name;
  }
}

var pig = {
  name: 'Jerry'
}

/**
 * 只处理了 参数为 string, number, object 的情况
 * @returns any
 */
Function.prototype.myBind = function() {
  if (arguments.length === 0) {
    return this
  } else {
    let context = arguments[0]
    // 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的
    if (context === null || context === undefined) return this()
    if (typeof context !== 'object') context = {}

    context[this.name] = this
    const that = this
    return function() {
      let arg
      let func = that.name + '('
      let myArgs = []
      for (let i = 0; i < arguments.length; i++) {
        arg = arguments[i]
        if (typeof arg === 'string') {
          if (i === 0) {
            func += `'${arg}'`
          } else {
            func += `,'${arg}'`
          }
        } else if (typeof arg === 'number') {
          if (i === 0) {
            func += arg
          } else {
            func += "," + arg
          }
        } else if (typeof arg === 'object') {
          myArgs.push(arg)
          if (i === 0) {
            func += `myArgs[${i}]`
          } else {
            func += `,myArgs[${i}]`
          }
        }
      }
      func += ')'
      console.dir(func)
      const result = eval('context.' + func)
      delete context[that.name]
      return result
    }
  }
}

console.log(person.sayHi.myBind(pig)({ name: 'c' }, { name: 'd' }))
// console.log(person.sayHi())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值