JavaScript之模拟实现Call、Apply

463 阅读1分钟

通过实现模拟call和apply,深入理解call和apply是如何改变this。

call

简单概述call:

call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。

举个栗子:

let baby = {
  name: "George"
}

function getName(age) {
  return {
    name: this.name,
    age
  }
}

getName.call(baby, 1) // {name: "George", age: 1}

注意:

  • call改变了this的指向,主到了baby
  • getName函数执行了

模拟实现

我们假设最后这样调用函数:

getName.simulateCall(baby, 1)

因为getName是函数,我们在Function.prototype上进行扩展。设想,函数的调用是在某个对象上触发的,即调用位置上存在上下文对象,例如XXX.getName()

var name = 'ALin'
let baby = {
  name: "George"
}

function getName(age) {
  return {
    name: this.name,
    age
  }
}

Function.prototype.simulateCall = function(context, ...args) {
  let ctx = context || window
  ctx.fun = this
  const result = ctx.fun(...args)
  delete ctx.fun
  return result
}
getName.call(baby, 1) // {name: "George", age: 1}
getName.call(null, 16) //{name: 'Alin', age: 16}
getName.simulateCall(baby, 1)  // {name: "George", age: 1}
getName.simulateCall(null, 18)  // {name: "Alin", age: 18}

apply的模拟实现

apply 的实现跟 call 类似,后面的参数格式为数组而已,直接上代码

var name = 'ALin'
let baby = {
  name: "George"
}

function getName(age) {
  return {
    name: this.name,
    age
  }
}

Function.prototype.simulateApply = function(context, args) {
  let ctx = context || window
  ctx.fun = this
  const result = ctx.fun(...args)
  delete ctx.fun
  return result
}

getName.apply(baby, [1]) // {name: "George", age: 1}
getName.apply(null, [1]) // {name: "Alin", age: 1}
getName.simulateApply(baby, [1]) // {name: "George", age: 1}
getName.simulateApply(null, [1]) // {name: "Alin", age: 1}

好了,辣么问题来了,如何模拟bind呢?

相关阅读

JavaScript之模拟实现new