深入熟悉call、apply、bind并手写

64 阅读2分钟

前言

call、apply、bind在日常开发中多多少少都会使用到它们,下面让我们来深入比较并熟悉。

介绍

它们其实都是有两个共同点:

  1. 用于函数调用call, bind, 和 apply 都用于调用函数。
  2. 设置函数上下文 :它们都允许您设置函数执行时的上下文对象(通常是函数内的 this)。

谈论到它们的区别的话,也是有两个不同的点:

  1. 参数传递方式 :
  • call: 接受一个函数的参数列表,依次传递给函数。
  • apply: 接受一个函数的参数数组,其中数组的每个元素依次传递给函数。
  • bind: 创建一个新的函数,将传递给 bind 的参数列表或数组绑定到函数上,并返回一个新函数,不立即执行。
  1. 立即执行 :
  • callapply 立即执行函数,它们会调用函数并传递参数。
  • bind 不会立即执行函数,它返回一个新函数,您需要显式调用该函数才会执行。

深入理解

我们现在来手写下它们,更好的熟悉下。

手写内容:

call

// call函数实现
Function.prototype.myCall = function (context) {
  // 判断调用对象
  if (typeof this !== "function") {
    console.error("type error");
  }
  // 获取参数
  let args = [...arguments].slice(1),
    result = null;
  // 判断 context 是否传入,如果未传入则设置为 window
  context = context || window;
  // 将调用函数设为对象的方法
  context.fn = this;
  // 调用函数
  result = context.fn(...args);
  // 将属性删除
  delete context.fn;
  return result;
};

apply

// apply 函数实现
Function.prototype.myApply = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  let result = null;
  // 判断 context 是否存在,如果未传入则为 window
  context = context || window;
  // 将函数设为对象的方法
  context.fn = this;
  // 调用方法
  if (arguments[1]) {
    result = context.fn(...arguments[1]);
  } else {
    result = context.fn();
  }
  // 将属性删除
  delete context.fn;
  return result;
};

bind

// bind 函数实现
Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this;
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(
      this instanceof Fn ? this : context,
      args.concat(...arguments)
    );
  };
};

总结

以上手写是我们日常工作和面试中常常遇到的,手写它们有助于我们更深入的理解它们的作用和原理。