1、✅彻底搞懂 call、apply 和 bind

✅《JS 手写系列》第 1 篇:彻底搞懂 callapplybind


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

  • 它们是 JavaScript 中 Function 原型链上非常核心的函数。
  • 实际开发中经常用于改变函数的执行上下文(this)。
  • 大厂面试高频必考(小公司不考别怕),考你理解 this、本质执行流程、原型继承。

🔍 二、面试官的考察重点

  • 你是否知道 call/apply/bind 本质上是让函数以指定 this 执行?

  • 你是否清楚区别:

    • call:立即执行 + 传参列表
    • apply:立即执行 + 传参数组
    • bind返回一个新函数,不立即执行

🧠 三、原理拆解与实现步骤

3.1 核心思路

js 复制代码
fn.call(obj, arg1, arg2)
// 等价于:obj.fn = fn; obj.fn(arg1, arg2); delete obj.fn

✍️ 四、手写 call

js 复制代码
Function.prototype.myCall = function (context, ...args) {
  context = context || globalThis; // 处理 null/undefined
  const fnSymbol = Symbol('fn'); // 防止属性覆盖
  context[fnSymbol] = this;      // this 是当前函数

  const result = context[fnSymbol](...args); // 执行函数
  delete context[fnSymbol];                 // 清理临时属性
  return result;                            // 返回结果
};

✅ 用例验证

js 复制代码
function greet(greeting, name) {
  console.log(`${greeting}, ${name} from ${this.city}`);
}
const context = { city: 'Guangzhou' };
greet.myCall(context, 'Hi', 'Mark'); // Hi, Mark from Guangzhou

✍️ 五、手写 apply

js 复制代码
Function.prototype.myApply = function (context, args) {
  context = context || globalThis;
  const fnSymbol = Symbol('fn');
  context[fnSymbol] = this;

  const result = Array.isArray(args)
    ? context[fnSymbol](...args)
    : context[fnSymbol]();

  delete context[fnSymbol];
  return result;
};

✅ 用例验证

js 复制代码
greet.myApply(context, ['Hello', 'Hao']); // Hello, Hao from Guangzhou

✍️ 六、手写 bind

js 复制代码
Function.prototype.myBind = function (context, ...args) {
  const self = this;

  return function (...restArgs) {
    return self.apply(context, [...args, ...restArgs]);
  };
};

✅ 用例验证

js 复制代码
const greetBound = greet.myBind(context, 'Yo');
greetBound('Fu'); // Yo, Fu from Guangzhou

🔁 七、进阶版本:支持 new 调用的 bind

js 复制代码
Function.prototype.myBind = function (context, ...args) {
  const self = this;

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

  // 原型继承
  boundFunction.prototype = Object.create(self.prototype);
  return boundFunction;
};

❗ 八、易错点总结(面试特别爱问)

错误理解 正确做法
bind 会立即执行 ❌,它返回一个函数,不会立即执行
没有处理 new 场景 ✅ 用 this instanceof 区分
覆盖对象属性名 ✅ 用 Symbol 解决
相关推荐
爱勇宝8 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
梨子同志9 小时前
常用命令
前端
梨子同志9 小时前
React 状态管理
前端
Dxy12393102169 小时前
MySQL索引完整教程:创建、查看、修改、删除与日常管理
前端·javascript·mysql
剪刀石头布啊10 小时前
js能被遍历的集合有哪些特征,为何能被遍历
前端
剪刀石头布啊10 小时前
js解构
前端
剪刀石头布啊10 小时前
防抖功能的逐步递进
前端
剪刀石头布啊10 小时前
对象的大小比较与面向对象思考
前端
端庄的战斗机11 小时前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
最爱老式锅包肉12 小时前
《HarmonyOS技术精讲-ArkWeb》桥接两岸:JSBridge原生与Web互调
前端·华为·harmonyos