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 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶8 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
Kagol11 小时前
🎉OpenTiny NEXT-SDK 重磅发布:四步把你的前端应用变成智能应用!
前端·开源·agent
GIS之路12 小时前
ArcGIS Pro 中的 notebook 初识
前端
JavaGuide12 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
ssshooter12 小时前
看完就懂 useSyncExternalStore
前端·javascript·react.js
格砸13 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端
Live0000014 小时前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native
柳杉14 小时前
使用Ai从零开发智慧水利态势感知大屏(开源)
前端·javascript·数据可视化