每个函数都包含从 Function.prototype 上继承而来的 三个方法: apply()call()bind(),这三个方法都会去影响函数运行时this的指向。

# apply 方法

作用与 call 方法作用类似,都是调用一个具有给定this值得函数,区别在于 参数传递的形式不一样,call()方法接受的是参数列表,而apply() 方法接受得是一个参数数组

apply() 方法接受两个参数:

  • 第一个参数就是指定运行函数得作用域(也就是给定得this值)
  • 第二个参数是一个数组,表示调用指定函数需要得参数列表

  function sum(num1,num2){
    return sum1 + num2
  }

  function sumApply(num1,num2){
    return sum.apply(this,arguments)  // 比如传入 arguments 等价于  sum.apply(this,[num1,num2]),这里得this值(因为是在全局作用域中调用得,所以`this`指向得是 `window`对象)是 window
  }

  const nums = [5,6,2,3,7]

  const max = Math.max.apply(null,nums)     // 7

手写 apply 方法

/**
 * apply 接收两个参数,第一个参数是 指定的 `this`值,第二个参数是 一个数组
 * apply 方法 返回的是 调用给定 this 值 和 指定函数得 结果
 * */
Function.prototype.MyApply = function (content=window){ 
  if(typeof this!== 'function') throw new Error('not function');  // 判断this 是不是一个函数

  content=content||window // 绑定上下文,没有则默认window

  const args = arguments[1] || []   // 获取参数

  content.fn = this // 在上下文对象上虚拟出一个fn 属性,将函数的this 作为对象的方法,从而this 会指向对象(content)

  const reuslt = content.fn(...args)  // 调用函数得到结果

  delete content.fn // 删除虚拟出来的 属性 fn

  return result // 返回结果
}

# call 方法

作用于 apply 方法类似,使用一个指定得this值和单独给出得一个或多个参数来调用一个函数。

call() 方法接受得参数: 第一个参数是给定得this值,后续参数是调用指定函数需要用到得参数

  function sum(num1,num2){
    return num1 + num2
  }

  function sumCall(num1,num2){
    return sum.call(this,...arguments)
  }

  const arr = [1,2,3,89,46]

  const max = Math.max.call(null,...arr)    // 89

手写 call 方法


/**
 *  call 方法接收得第一个参数为 给定得 this 值,剩余得参数都是 调用指定函数所需要传递得参数
 *  call 方法 返回得是调用指定函数得 结果
 * */

Function.prototype.MyCall = function(content){ 
  if(typeof this !=='function') throw new Error('not function')

  content=content||window // 绑定上下文,没有则默认window

  const args = [...arguments].slice(1)  // 获取调用指定函数所需要得参数

  content.fn = this     // 在上下文对象上虚拟出一个fn 属性,将函数的this 作为对象的方法,从而this 会指向对象(content)

  const result = content.fn(...args)  // 调用指定函数

  delete content.fn // 删除虚拟出来得fn 属性

  return result // 返回结果

}

# bind 方法

bind 方法得作用是创建一个新的函数,在 bind() 时被调用,这个新函数得this 被指定为bind()得第一个参数,而其余参数将作为新函数得参数,供调用时使用。

bind得返回值是函数

bind 得参数形式 跟 call 类似: 第一个参数是 this得指向,从第二个参数开始是接受得参数列表,区别


const module = {
  x:42,
  getX:function(){
    console.log(this.x)
  }
}

const unboundGetX = module.getX

const boundGetX = unboundGetX.bind(module)

unboundGetX()   // undefined     函数 unboundGetX得 作用域是全局作用域,因此 unboundGetX 函数内部得this 指向得是 window 对象

boundGetX()     // 42

手写 bind 方法


/**
 * bind 方法接收得参数于 call 类似,第一个参数为给定得`this`值,剩余得参数为调用指定函数所需传递得参数
 * bind 方法返回得是一个函数
 * */

Function.prototype.MyBind = function(content){ 
  if(typeof this !=='function') throw new Error('not function')

  content=content||window // 绑定上下文,没有则默认window

  let _self = this  // 保存this(函数)

  let args = [...arguments].slice(1)  // 获取参数
  
  // 实现新函数

  let bound = function(){
    // 合并参数
    let finalArgs = args.concat([...arguments])
    // 如果this 是bound 得实例,及使用 new 方法调用 bound
    if(this instanceof bound){
      // 原型集成
      if(_self.prototype){
        this.prototype = Object.create(_self.prototype)
      }
      // 如果返回得不是引用类型得值,就返回this
      let result = this.apply(this,finalArgs)
      let isObject = typeof result === 'object' && result !== null
      let isFunction = typeof result === 'function'
      if(isObject || isFunction) return result
    }

    // 修改this 指向,返回结果
    return _self.apply(content,finalArgs)
  }

  return bound
}

最后更新时间: 2/21/2022, 3:29:09 PM