手写 call、apply、bind

91 阅读1分钟

一、实现思路

1.call 和 apply 实现思路主要是:

call 和 apply 实现思路主要是:

  • 判断是否是函数调用,若非函数调用抛异常
  • 通过新对象(context)来调用函数
  • 给 context 创建一个 fn 设置为需要调用的函数
  • 结束调用完之后删除 fn

2.bind 实现思路

  • 判断是否是函数调用,若非函数调用抛异常
  • 返回函数
  • 判断函数的调用方式,是否是被 new 出来的
  • new 出来的话返回空对象,但是实例的__proto__指向_this 的prototype
  • 完成函数柯里化

二、代码实现

  • call
Function.prototype.myCall = function (context) {
    // 先判断调用 myCall 是不是一个函数 
    // 这里的 this 就是调用 myCall 的 
    if (typeof this !== 'function') {
        throw new TypeError("Not a Function") 
    } 
    // 不传参数默认为 window 
    context = context || window 
    // 保存 
    this context.fn = this
    // 保存参数 
    let args = Array.from(arguments).slice(1) 
    //Array.from 把伪数组对象转为数组 
    // 调用函数 
    let result = context.fn(...args) 
    delete context.fn 
    return result 
}
  • apply
Function.prototype.myApply = function (context) { 
    // 判断 this 是不是函数 
    if (typeof this !== "function") { 
        throw new TypeError("Not a Function") 
    }
    let result 
    // 默认是 window 
    context = context || window 
    // 保存
    this context.fn = this
    // 是否传参 
    if (arguments[1]) { 
        result = context.fn(...arguments[1]) 
    } else { 
        result = context.fn() 
    } 
    delete context.fn
    return result
}
  • bind
Function.prototype.myBind = function (context) {
  // 判断是否是一个函数
  if (typeof this !== "function") {
    throw new TypeError("Not a Function");
  }
  // 保存调用 bind 的函数
  const _this = this;
  // 保存参数
  const args = Array.prototype.slice.call(arguments, 1);
  // 返回一个函数
  return function F() {
    // 判断是不是 new 出来的
    if (this instanceof F) {
      // 如果是 new 出来的
      // 返回一个空对象,且使创建出来的实例的__proto__指向_this 的prototype,且完成函数柯里化
      return new _this(...args, ...arguments);
    } else {
      // 如果不是 new 出来的改变 this 指向,且完成函数柯里化
      return _this.apply(context, args.concat(...arguments));
    }
  };
};