快速手撕call、apply、bind

81 阅读3分钟

call和apply方法

作用:调用函数并改变函数内this的指向

语法:

两种方法都是属于函数对象的,所以必须是函数对象才能调用

functionName.call(obj,实参1,实参2...)
functionName.apply(obj,[参数1,参数2...])

区别:

  • 都是改变函数内this的指向
  • call方法参数是一个一个传递,而apply是传递一个参数数组

特殊情况:如果传递的第一个伪造对象是null或undefined,则函数内this会指向window全局对象

function test(a,b){
    console.log(this,a,b)
}  
test.call(null,10,20)
test.apply(undefined,[10,20])

什么时候用call或apply

理解:call或apply就是一种高端调用函数的方式

  1. 可改变函数内this指向
  2. 改变传参的方式

bind方法

  • bind的作用和call/apply差不多,都是改变函数内this的指向。区别在于,bind不是立即执行,而是返回一个新函数。
  • bind方法也是是属于函数对象的,所以必须是函数对象才可以调用。

functionName.bind(obj,实参数1,实参数2...)

function test(a, b) {
   console.log(this.age, 'a:', a, ' b:', b);
}

var obj = { age: 18 }
var fn = test.bind(obj, 50, 60) // 这里test并不会立即执行而是会返回一个函数
fn()

call/apply/bind三者区别:

  • 相同点:都可以改变函数内this的指向
  • 不同点:call/apply是立即执行的,而bind是返回一个新函数

手撕call、apply、bind

function test(a, b) {
    console.log(this)
    console.log(arguments)
}
const obj = {
    name: 'zs',
    age: 18,
}

call

/*
         1.获取第一个参数,判断context是否为undefined或null,是的话this指向window
         2.创建一个临时的方法接收调用myCall的执行函数
         3.获取参数并执行对应的函数
         4.删除创建的临时方法,消除副作用
         5.返回结果
     */
   Function.prototype.myCall = function (context, ...args) {
      // 判断context是否为undefined或null,是的话this指向window
      context = context || window
      // 创建一个临时的函数接收调用myCall的执行函数
      context.fn = this
      // this为调用myCall的函数,即function test(){}
      console.log(this)
      // 获取参数并执行对应的函数
      let res = context.fn(...args)
      // 删除创建的临时方法
      delete context.fn
      // 返回结果
      return res
   }
   test.myCall(obj, 1, 2)
   /* 输出结果为:
         ƒ test(a, b) {
       console.log(this)
       console.log(arguments)
    }
     {name: 'zs', age: 18}
     Arguments(2)
    */

apply

	/*
         apply与call非常类似,只是传入第二个参数(args)时需要传一个数组
   */
   Function.prototype.myApply = function (context, args) {
      // 判断context是否为undefined或null,是的话this指向window
      context = context || window
      // 创建一个临时的函数接收调用myCall的执行函数
      context.fn = this
      // this为调用myCall的函数,即function test(){}
      console.log(this)
      // 获取参数并执行对应的函数
      let res = context.fn(...args)
      // 删除创建的临时方法
      delete context.fn
      // 返回结果
      return res
   }
   test.myApply(obj, [1, 2])
    /* 输出结果为:
         ƒ test(a, b) {
           console.log(this)
           console.log(arguments)
        }
         {name: 'zs', age: 18}
         Arguments(2)
    */

bind

   /* 
        bind与call与apply的最大区别是返回的是一个函数而不是立即执行
        bind的参数也是一个一个传入与call类似
        但是bind会有两拨参数,第一组参数是调用bind(...args1),第二组参数是调用bind后返回的函数function (...args2)
   */
   Function.prototype.myBind = function (context, ...args1) {
      // 判断context是否为undefined或null,是的话this指向window
      context = context || window
      context.fn = this
      // bind最大区别就是返回一个函数而不是立即执行
      return function (...args2) {
         context.fn(...args1, ...args2)
         delete context.fn
      }
   }

   let res = test.myBind(obj, 1, 2, 3)
   res(4, 5, 6)
   /* 
        输出结果为:
        {name: 'zs', age: 18}
        Arguments(6) // [1, 2, 3, 4, 5, 6]
   */