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 解决
相关推荐
书唐瑞5 分钟前
谷歌浏览器和火狐浏览器对HTML的嗅探(Sniff)能力
前端·html
rocky19114 分钟前
谷歌浏览器插件 使用 playwright 回放用户动作键盘按键特殊处理方案
前端
rocky19117 分钟前
playwright里兼容处理回放无界微前端内iframe内部元素事件和不在无界微前端内的iframe元素
前端
rocky19119 分钟前
谷歌浏览器插件 使用 playwright 回放slide 拖动动作
前端
Devil枫22 分钟前
HarmonyOS鸿蒙应用:仓颉语言与JavaScript核心差异深度解析
开发语言·javascript·ecmascript
惺忪979833 分钟前
回调函数的概念
开发语言·前端·javascript
xxxxxxllllllshi40 分钟前
【Elasticsearch查询DSL API完全指南:从入门到精通】
java·大数据·elasticsearch·搜索引擎·面试·全文检索·jenkins
前端 贾公子44 分钟前
Element Plus组件v-loading在el-dialog组件上使用无效
前端·javascript·vue.js
天外飞雨道沧桑1 小时前
JS/CSS实现元素样式隔离
前端·javascript·css·人工智能·ai
程序0071 小时前
前端写一个密码登录,验证码登录,注册模板
前端