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 解决
相关推荐
东宇科技17 小时前
如何使用js进行抠图。识别商品主体
开发语言·javascript·ecmascript
不会写DN17 小时前
Vue3中的computed 与 watch 的区别
javascript·面试·vue
qq_3813385017 小时前
TypeScript 类型安全与类型体操实战:从入门到精通
javascript·安全·typescript
朦胧之17 小时前
AI 编程工具使用浅谈
前端·后端
柳杉17 小时前
HTML-in-Canvas:让 Canvas 完美渲染 HTML 的 Web 新标准
前端·javascript
cTz6FE7gA17 小时前
WebGL实战:用Three.js创建3D场景,实现沉浸式Web体验
前端·javascript·webgl
不会写DN17 小时前
IPv4 与 IPv6 的核心区别
计算机网络·面试·golang
chh56317 小时前
C++--内存管理
java·c语言·c++·windows·学习·面试
We་ct17 小时前
LeetCode 69. x 的平方根:两种解法详解
前端·javascript·算法·leetcode·typescript·平方
qq. 280403398417 小时前
数据结构引论
前端·数据结构