手写apply,call,bind

58 阅读3分钟

方法介绍

apply

apply()方法的作用是改变一个函数的执行环境,通俗的理解为可以改变this的指向

function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '李华'}
fn.apply(obj, [1,2,3])

// 打印结果  李华,1,2,3

分析:我们的obj对象没有fn函数,但是现在它可以fn函数,这就是我们要达到的效果

手写call

Function.prototype.myCall = function (context, ...args) {
    // this就是函数的调用者,例如fn.apply(null,args),此处的this就是fn
    if (typeof this !== 'function') {
        return;
    }
    // context为要绑定的对象,即最终谁来调用函数,如果传入的是null,就绑定globalThis(ES11)
    const self = context || globalThis;
    // 定义一个唯一的key,不可重复
    let key = Symbol();
    // 把调用函数赋值给新属性,self原来的属性依然存在
    self[key] = this;
    // 调用函数获取结果
    const result = self[key](...args);
    // 保持原属性不发生变更,删掉属性
    delete self[key];
    return result;
}

function fn(a, b, c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = { name: '李华' }
fn.myCall(obj, 1, 2, 3)

手写apply

Function.prototype.myApply = function (context, args) {
    // this就是函数的调用者,例如fn.apply(null,args),此处的this就是fn
    if (typeof this !== 'function') {
        return;
    }
    // context为要绑定的对象,即最终谁来调用函数,如果传入的是null,就绑定globalThis(ES11)
    const self = context || globalThis;
    // 定义一个唯一的key,不可重复
    let key = Symbol();
    // 把调用函数赋值给新属性,self原来的属性依然存在
    self[key] = this;
    // 调用函数获取结果
    const result = self[key](...args);
    // 保持原属性不发生变更,删掉属性
    delete self[key];
    return result;
}

function fn(a, b, c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = { name: '李华' }
fn.myApply(obj, [1, 2, 3])

apply和call的本质是一样的,只是入参不一样,apply第二个参数传入的是数组,而call传的就是所有参数,所有两个手写的区别就是形参,如果是apply,传入的是数组,就在形参上把入参解构

bind使用

bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数, 它的参数是 bind() 的其他参数和其原本的参数。 (这里需要注意bind返回的是一个函数,bind自身不会立即执行这个函数;而apply和call立即执行这个函数,返回执行后的结果)

function fun(arg1, arg2) {
    console.log(this.name)
    console.log(arg1 + arg2)
  }
  const _this = { name: 'YIYING' }
  // 只变更fun中的this指向,返回新function对象
  const newFun = fun.bind(_this)
  newFun(1, 2)
  
  // 输出YIYING  3

手写bind

Function.prototype.myBind = function (context, ...args) {
    // 1. 确定要绑定的对象,即最终谁来调用函数,命名为new_this;若没有传入要绑定的对象, 默认绑定window对象
    context = context || globalThis

    let fn = this;
    // 2. 把原函数(即this)用一个fn变量保存一下,这样更能看出它表示一个函数 
    return function newFn (...fnArgs) {
      let res
      // 3.要考虑新函数是不是会当作构造函数
      if (this instanceof newFn) {
        // 如果是构造函数则调用new 并且合并参数args,fnArgs
        res = new fn(...args, ...fnArgs)
      } else {
        // 当作普通函数调用 也可以用上面定义的myCall
        res = fn.call(context, ...args, ...fnArgs)
      }
      return res
    }
}