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 解决
相关推荐
猿大师播放器7 分钟前
猿大师中间件:Chrome网页内嵌PhotoShop微信桌面应用程序
前端·chrome
excel9 分钟前
Node.js + TensorFlow.js(GPU 加速)完整安装指南(Windows 本地编译版)
前端·后端
小磊哥er9 分钟前
【办公自动化】如何使用Python操作PPT和自动化生成PPT?
前端
前端小巷子9 分钟前
深入理解 Vue Router
前端·vue.js·面试
未来之窗软件服务16 分钟前
企业收款统计:驱动业务决策的核心引擎设计开发——仙盟创梦IDE
javascript·css3·仙盟创梦ide·东方仙盟·企业收款码
月熊38 分钟前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
艾小码43 分钟前
HTML5 & CSS3 从入门到精通:构建现代Web的艺术与科学
前端·css3·html5
yqcoder1 小时前
【无标题】
开发语言·javascript·ecmascript
袁煦丞2 小时前
OpenKylin 桌面系统,开源自由,跨界协作:cpolar内网穿透实验室第624个成功挑战
前端·程序员·远程工作
excel2 小时前
JavaScript 尾递归优化详解
前端