call & apply & bind 原理

135 阅读2分钟

1.实现 call

Function.prototype._call = function (thisArg, ...args) {
  // 1.将thisArg转成对象类型(防止传入的是非对象类型)
  thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
    
  // 2.定义唯一key
  const symbolFn = Symbol(+new Date) 

  // 3.获取需要执行的函数
    Object.defineProperty(thisArg, symbolFn, { get: () => this, configurable: true })

  // 4.调用需要被执行的函数
  const result = thisArg[symbolFn](...args)

  // 5.删除symbolFn属性
  delete thisArg[symbolFn]
  
  // 6.将结果返回出去
  return result
}
  • 测试代码
const lain = {
  name: 'lain',
  age: 16,
  friends: []
}

function foo(...newFriends) {
  console.log(newFriends) // ['小鸟游六花', '樱岛麻衣', '伊莉雅']
  this.friends.push(...newFriends)
  console.log(this) // {name: 'lain', age: 16, friends: Array(3), fn: ƒ}
}
foo._call(lain, '小鸟游六花', '樱岛麻衣', '伊莉雅') 

2. 实现 apply

Function.prototype._apply = function (thisArg, argArray = []) {
  // 1.将thisArg转成对象类型(防止传入的是非对象类型)
  thisArg = (thisArg !== undefined && thisArg !== null) ? Object(thisArg) : window

  // 2.定义唯一key
  const symbolFn = Symbol(+new Date)
    
  // 3.获取需要执行的函数
  Object.defineProperty(thisArg, symbolFn, { get: () => this, configurable: true })

  // 4.调用需要执行的函数
  const result = thisArg[symbolFn](...argArray)

  // 5.删除fn属性
  delete thisArg[symbolFn]

  // 6.将结果返回出去
  return result
}
  • 测试代码
const lain = {
  name: 'lain',
  age: 16,
  friends: []
}

function foo(...newFriends) {
  console.log(newFriends) // ['小鸟游六花', '樱岛麻衣', '伊莉雅']
  this.friends.push(...newFriends)
  console.log(this) // {name: 'lain', age: 16, friends: Array(3), fn: ƒ}
}
foo._apply(lain, ['小鸟游六花','樱岛麻衣','伊莉雅'],'saber')

3.实现 bind

Function.prototype._bind = function (thisArg,argArray) {
  // 1.将thisArg转成对象类型(防止传入的是非对象类型)
  thisArg = (thisArg !== undefined && thisArg !== null) ? Object(thisArg) : window
  
  // 2.定义唯一key
  const symbolFn = Symbol(+new Date)
     
  // 3.获取需要执行的函数
  Object.defineProperty(thisArg, symbolFn, { get: () => this, configurable: true })

  // 4.返回函数地址以便调用
  return (...args) => {
    const result = thisArg[symbolFn]([...argArray, ...args])
   
    // 5.删除fn函数
	delete thisArg[symbolFn]
      
    // 6.将结果返回出去
    return result
  }
}
  • 测试代码
const lain = {
  name: 'lain',
  age: 16,
  friends: []
}

function foo(newFriends) {
  console.log(newFriends) // ['小鸟游六花', '樱岛麻衣', '伊莉雅', '五河琴里]
  this.friends.push(...newFriends)
  console.log(this) // {name: 'lain', age: 16, friends: Array(4), fn: ƒ}
}
foo._bind(lain, ['小鸟游六花', '樱岛麻衣', '伊莉雅'])('五河琴里')