出处:掘金

原作者:金泽宸


为什么要手写这几个函数?

核心思路

fn.call(obj, arg1, arg2)

// 等价于:
obj.fn = fn
obj.fn(arg1, arg2)
delete obj.fn

手写 call

Function.prototype.myCall = function (context, ...args) {
  // 1. 处理 context 的边界情况(null/undefined/原始值)
  if (context === null || context === undefined) {
      context = globalThis; // 非严格模式下,默认指向全局对象
  } else if (typeof context !== 'object') {
      context = new Object(context); // 原始值转换为包装对象(如数字 1 → Number 对象)
  }

  // 2. 用 Symbol 创建唯一属性,避免覆盖 context 原有属性
  const uniqueThis = Symbol('unique');
  context[uniqueThis] = this; // this 是当前函数

  // 3. 调用函数,此时函数内部的 this 指向 context
  const result = context[uniqueThis](...args);

  // 4. 删除临时属性,避免污染 context
  delete context[uniqueThis];

  // 5. 返回函数执行结果
  return result;
};

手写 apply

Function.prototype.myApply = function (context, args) {
  // 1. 处理 context 的边界情况(null/undefined/原始值)
  if (context === null || context === undefined) {
      context = globalThis; // 非严格模式下,默认指向全局对象
  } else if (typeof context !== 'object') {
      context = new Object(context); // 原始值转换为包装对象(如数字 1 → Number 对象)
  }
  
  // 2. 用 Symbol 创建唯一属性,避免覆盖 context 原有属性
  const uniqueThis = Symbol('unique');
  context[uniqueThis] = this; // this 是当前函数
  
  // 3. 调用函数,此时函数内部的 this 指向 context
  const result = Array.isArray(args)
    ? context[uniqueThis](...args)
    : context[uniqueThis]();
  
  // 4. 删除临时属性,避免污染 context
  delete context[uniqueThis];
  
  // 5. 返回函数执行结果
  return result;
};

手写 bind

基础版

Function.prototype.myBind = function (context, ...outArgs) {
  // 1. 判断 context 类型
  if (context === undefined || context === null) {
    context = globalThis;
  } else {
    context = Object(context);
  }

  // 2.唯一属性保存
  const uniquePrototype = Symbol("unique");
  context[uniquePrototype] = this;

  // 3.返回调用的函数
  return function (...innerArgs) {
    return context[uniquePrototype](...outArgs, ...innerArgs);
  };
};

缺陷:

进阶版

Function.prototype.myBind = function (context, ...outArgs) {
  const self = this;

  function boundFunction(...innerArgs) {
    // 如果是用 new 调用
    if (this instanceof boundFunction) {
      return new self(...outArgs, ...innerArgs);
    }
    return self.apply(context, [...args, ...restArgs]);
  }

  // 原型继承
  boundFunction.prototype = Object.create(this.prototype);

  // 添加 unbind 方法,返回原始函数
  boundFunction.unbind = () => self;

  return boundFunction;
};

常见易错点

错误理解 正确做法
bind 会立即执行 ❌,它返回一个函数,不会立即执行
没有处理 new 场景 ✅ 用 this instanceof 区分
覆盖对象属性名 ✅ 用 Symbol 解决