call 是 JavaScript 中非常核心的函数方法之一。它能改变函数的执行上下文(也就是 this 的指向),在日常开发和面试中都极其常见。本文将带你一步步实现一个 Function.prototype.call 的自定义版本,真正理解它的底层原理。


✨ 一、call 方法做了什么?

在 MDN 中,Function.prototype.call() 是这样定义的:

call() 方法使用一个指定的 this 值和若干个指定的参数(参数的列表)来调用一个函数。

通俗来讲,它的作用就是:

  • 显式指定函数的 this 指向;

  • 并立即执行该函数;

  • 参数可以依次传入。


📌 二、原生 call 的底层逻辑拆解

来看一段模拟的执行逻辑:

var obj = {x: 100,fn() {console.log(this.x);}
};
obj.fn(); // 输出 100

上面 fn() 的 this 指向 obj,因为是以 obj.fn() 的形式调用。

call 就是模拟了类似的过程——把函数挂载到目标对象上执行,从而实现 this 指向绑定。


🧠 三、call 方法内部做了哪些事?

  1. 判断传入的 context(目标对象)是否为值类型(如字符串、数字),如果是,就转为对象(如 'abc'new String('abc'));

  2. 将函数临时设为 context 的属性;

  3. 通过 context.fn() 执行函数,此时 this 指向 context;

  4. 删除临时挂载的函数属性,防止污染;

  5. 返回函数的执行结果。


🔧 四、手动实现 call 方法(完整版)

Function.prototype.myCall = function (context = window, ...args) {if (typeof context !== 'object' && typeof context !== 'function') {context = new Object(context); // 将值类型转换为对象}const fnKey = Symbol();       // 创建唯一属性名,避免覆盖已有属性context[fnKey] = this;        // this 是当前函数,即被调用的函数const result = context[fnKey](...args); // 执行函数,绑定 this 并传参delete context[fnKey];        // 清理属性,防止污染return result;                // 返回函数执行结果
};

🧪 五、测试用例验证

function f(a, b) {console.log(a + b);       // 输出 3console.log(this.name);   // 输出 1
}const obj = { name: 1 };
f.myCall(obj, 1, 2);        // 等价于 f.call(obj, 1, 2)

输出结果:

3
1

💬 六、值类型绑定说明

function print() {console.log(this);
}print.myCall('abc'); // this → String 对象:new String('abc')

值类型(如字符串、数字)在传入时会被自动装箱为对象类型。


🚧 七、边界情况优化建议

  • 如果 contextnullundefined,原生 call 会将 this 指向全局对象(非严格模式),或 undefined(严格模式);

  • 也可以通过判断加以处理:

context = context ?? window;

🎯 八、面试高频拓展:call vs apply vs bind

方法名作用参数传入方式是否立即执行
call改变 this 并执行函数参数列表✅ 是
apply改变 this 并执行函数参数数组✅ 是
bind改变 this,返回新函数参数列表❌ 否(需手动执行)

📎 九、小结

手动实现 call 的过程并不复杂,但却是理解 JavaScript 中函数和 this 机制的关键一步。建议掌握以下重点:

  • this 的绑定原理(对象调用 vs 普通调用)

  • 值类型的自动装箱

  • 如何通过函数挂载 + Symbol 解决属性污染

  • 面试中可以延伸讲解 applybind 的区别


🎁 十、完整源码

Function.prototype.myCall = function (context = window, ...args) {if (typeof context !== 'object' && typeof context !== 'function') {context = new Object(context);}const fnKey = Symbol();context[fnKey] = this;const result = context[fnKey](...args);delete context[fnKey];return result;
};

如果你觉得这篇文章有帮助,欢迎点赞 👍 收藏 ⭐ 评论 💬 交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91475.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91475.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/91475.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言中的盲点:竞态检测和互斥锁的错觉

🧠 Go语言中的盲点:竞态检测和互斥锁的错觉 使用 -race 就能发现所有并发问题?加了 mutex 就万无一失? 这篇文章揭示了 Go 并发编程中的一个“危险盲区” —— 互斥锁并不能总能保护你免受数据竞争的影响,尤其是在 -ra…

从文件到文件描述符:理解程序与文件的交互本质

一、理解文件 抛一个概念: 文件 内容 属性。 1. 那么,空文件有大小吗?答案是有的。因为空文件指的是文件内容为空,文件属性也要占据大小啊。 将来对文件操作,无非分为两类: 1.对文件内容做修改。 2.对文件…

优化算法专栏——阅读导引

前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…

[ The Missing Semester of Your CS Education ] 学习笔记 Vim篇

“Writing English words and writing code are very different activities. When programming, you spend more time switching files, reading, navigating, and editing code compared to writing a long stream.” —— < The Missing Semester of Your CS Education &g…

Linux 系统中定时执行指定命令 crontab 定时任务配置

crontab 定时任务配置是 Linux/Unix 系统中用于自动、周期性执行指定命令或脚本的工具&#xff0c;相当于系统的 “定时闹钟”。它可以让系统在预设的时间&#xff08;如每天凌晨、每周一、每月 1 号等&#xff09;自动完成重复性工作&#xff0c;无需人工干预。自动化运维定期…

[ Leetcode ]---快乐数

题目链接 Leetcode快乐数 题目描述 如下图&#xff1a; 题目解析&#xff1a; 1.双指针法 算法核心思路 判断快乐数的关键挑战是如何检测是否进入无限循环。这里使用了快慢指针法&#xff08;Floyd 循环检测算法&#xff09;&#xff0c;这是一种高效检测循环的技巧&#…

智慧社区构建——2

1.实现Token校验## Token校验URLjson GET /checkToken 参数json HttpServletRequest request 返回json {"msg": "操作成功","code": 200,"status": "ok" }{"msg": "操作成功","code": 200,&q…

K-Means聚类:当数据没有标签时,如何让计算机自动“物以类聚”?

K-Means聚类&#xff1a;当数据没有标签时&#xff0c;如何让计算机自动“物以类聚”&#xff1f;&#x1f44b; 大家好&#xff0c;我是小瑞瑞&#xff01;欢迎回到我的专栏&#xff01; 在我们之前的旅程中&#xff0c;解决的问题大多都有一个明确的“目标”&#xff0c;比如…

万事皆可用 GeeLark AI

在今年4月&#xff0c;GeeLark AI 全面接入 DeepSeek AI 大模型&#xff0c;你可以在独立窗口中便捷地使用 GeeLark AI。除了帮助你编写文案等基础内容&#xff0c;在使用 GeeLark 过程中&#xff0c;如果遇到问题&#xff0c;也可以通过询问 GeeLark AI&#xff0c;及时获取帮…

3D 高保真处理:声网让游戏声音随角色动作变化

传统游戏的声音体验像老式收音机&#xff0c;不管声源位置、距离和障碍物&#xff0c;仅靠左右声道机械调音量&#xff0c;毫无方向感和空间感&#xff0c;如同蒙眼听声辨位。射击游戏中敌人从左边来&#xff0c;耳机却两边同响且音量相近&#xff0c;让人晕头转向&#xff1b;…

Nestjs框架: 请求生命周期与应用生命周期

概述 在 NestJS 框架中&#xff0c;中间件&#xff08;Middleware&#xff09;、管道&#xff08;Pipes&#xff09;、过滤器&#xff08;Filters&#xff09;、拦截器&#xff08;Interceptors&#xff09; 均属于请求处理流程的核心组件&#xff0c;它们共同构成了 NestJS 的…

Nastool+cpolar:群晖NAS用户的全场景影音自由方案

文章目录前言1. 本地搭建Nastool2. nastool基础设置3. 群晖NAS安装内网穿透工具4. 配置公网地址小结5. 配置固定公网地址**第二版&#xff1a;技术整合与效率提升导向****第二版&#xff1a;技术整合与效率提升导向****第二版&#xff1a;技术整合与效率提升导向**Nastool与cpo…

从零开始:Kaggle 竞赛实战入门指南

一、Kaggle社区概述 Kaggle 是全球最大的数据科学和机器学习社区&#xff0c;由Anthony Goldbloom于2010年创立&#xff0c;2017年被Google收购。平台专注于数据科学竞赛、开源数据集共享、协作编程以及技能学习&#xff0c;吸引了从初学者到专业数据科学家的广泛用户群体。 …

sqli-labs:Less-16关卡详细解析

1. 思路&#x1f680; 本关的SQL语句为&#xff1a; $uname".$uname."; $passwd".$passwd."; $sql"SELECT username, password FROM users WHERE username($uname) and password($passwd) LIMIT 0,1";注入类型&#xff1a;字符串型&#xff08;…

Lipschitz连续函数

Lipschitz function 一、说明 在数学分析中&#xff0c;Lipschitz连续性以德国 数学家 鲁道夫利普希茨 (Rudolf Lipschitz)的名字命名&#xff0c;是函数一致连续性的强形式。直观地说&#xff0c;Lipschitz连续函数的变化速度有限&#xff1a;存在一个实数&#xff0c;使得对于…

Dynamics 365 business central 与Shopify集成

Dynamics 365 Business Central&#xff08;简称 D365 BC&#xff09; 与 Shopify 的集成&#xff0c;能帮助企业实现前端电商平台&#xff08;Shopify&#xff09;与后端 ERP 系统&#xff08;Business Central&#xff09;之间的无缝数据同步&#xff0c;是一种典型的 ERP 与…

TCP RTO 与丢包检测

TCP RTO 是它 40 多年前唯一丢包检测策略&#xff0c;也是当前最后的丢包检测兜底策略&#xff0c;它几乎从没变过。 有个咨询挺有趣&#xff0c;以其案例为背景写篇随笔。大致意思是&#xff0c;嫌 TCP RTO 太大&#xff0c;游戏场景丢包卡顿怎么办&#xff1f;我提供了几行代…

安装php和配置环境变量

为了简单方便&#xff0c;先下载vscode然后下载对应的php安装包&#xff0c;然后配置环境变量&#xff0c;然后点击运行即可下载对应版本的php&#xff0c;这个版本凑合用然后下载完之后解压配置环境变量搜索环境变量将路径添加到环境变量中然后打开vscode添加变量具体看实际路…

Rabbit MQ的消息模式-Java原生代码

一.简单模式1.1.核心逻辑生产者 → 队列 → 单个消费者&#xff08;1:1 直连&#xff09;&#xff0c;消息被消费后自动从队列删除。1.2.关键特性无交换器&#xff08;其实使用的是默认交换机不是显示指定&#xff09;&#xff0c;直接指定队列 消息默认自动确认&#xff08;au…

【lucene】使用docvalues的案例

下面给出一段 可直接跑通 的 Lucene 8.5.0 示例代码&#xff0c;演示如何1. 建索引时为两个字段启用 DocValues&#xff08;一个 NumericDocValues&#xff0c;一个 SortedDocValues&#xff09;&#xff1b; 2. 用 IndexSearcher 按 DocValues 排序&#xff1b; 3. 用 Facet…