Loading

模拟 call、apply、bind 方法

模拟 call 方法

关于 call 方法:

  • 某个方法/函数中的 this 总是指向调用该方法的对象
  • 直接调用函数,则函数中的 this 指向的是 window
  • 使用函数原型上的 call 方法可以修改 this 的指向为指定对象

思路:

  • 首选需要明确:实现自定义的 newCall 方法,需要将该方法定义在函数原型上
  • 我们有一个普通的函数 person,现在需要实现的是修改 personthis 指向到指定对象,如 foo
  • 将 person 存储为指定对象 foo 的临时方法
  • 通过 foo.person 调用该方法的时候,this 指向的当然就是 foo 对象了
  • 临时方法调用完后删除
Function.prototype.newCall = function (context) {
  var context = context || window // 若 context 是 null,最后 this 指向 window
  // this 指向的是调用 newCall 函数的对象,也就是 person 函数
  context.fn = this // 给这个上下文对象添加一个 fn 属性指向调用的函数
  // arguments 为伪数组,需要转换成数组才能使用数组方法
  var args = [...arguments].slice(1)
  var res = context.fn(...args)

  // 使用完删除 fn 这个属性
  delete context.fn
  return res
}

测试:

function person(name, age) {
  console.log(name, age)
  console.log(this.value)
}

var foo = { value: 100 }
person.newCall(foo, 'Danny', 18)

模拟 apply 方法

关于 apply 方法

  • 使用函数原型上的 apply 方法可以修改 this 的指向为指定对象
  • 区别于 call 的地方在于,apply 传入的参数为数组
  • 实现思路跟 call 基本一致
Function.prototype.newApply = function(context, arr) {
  // 将函数绑定到上下文对象中执行
  var context = context || window
  context.fn = this

  var res
  if (!arr) { // 没有传入任何参数, arr 为 undefined
    res = context.fn()
  } else {
    res = context.fn(...arr)
  }
  // 执行完后删除在对象添加的 fn 属性
  delete context.fn
  return res
}

测试:

function person(name, age) {
  console.log(name, age)
  console.log(this.value)
}

var foo = { value: 100 }
person.newApply(foo, ['Danny', 18])

模拟 bind 方法

关于 bind 方法

  • bind 方法区别于 call 的地方在于,调用 bind 返回的是一个函数
  • 要实现 call 的效果,需要在返回的函数基础上再进行一次调用
  • 可以借助 apply 来实现 bind 方法
Function.prototype.newBind = function () {
  // 拿到所有参数,将伪数组转为数组
  const args = [...arguments]
  // 获取 context
  const context = args.shift()
  // 获取 fn,即待执行函数 fn.bind(...) 中的 fn
  const fn = this
  return function () {
    return fn.apply(context, args)
  }
}

测试:

function person(name, age) {
  console.log(name, age)
  console.log(this.value)
}

var foo = { value: 100 }
var fn = person.newBind(foo, 'Danny', 18)
fn()
posted @ 2021-11-17 18:49  neoscar  阅读(30)  评论(0编辑  收藏  举报