this、箭头函数与普通函数:前端实战避坑指南 | JS 基础语法与数据操作篇

this、箭头函数与普通函数:前端实战避坑指南 | JS 基础语法与数据操作篇
【this/箭头函数/普通函数】+【前端中后台开发】:从【this绑定逻辑】到【落地实操】,彻底搞懂【函数选型】的最佳写法,避开Promise/模板事件/对象方法高频坑!
在这里插入图片描述

📑 文章目录


同学们好,我是 Eugene(尤金),一个拥有多年中后台开发经验的前端工程师~

(Eugene 发音很简单,/juːˈdʒiːn/,大家怎么顺口怎么叫就好)

你是否也有过:明明学过很多技术,一到关键时候却讲不出来、甚至写不出来?

你是否也曾怀疑自己,是不是太笨了,明明感觉会,却总差一口气?

就算想沉下心从头梳理,可工作那么忙,回家还要陪伴家人。

一天只有24小时,时间永远不够用,常常感到力不从心。

技术行业,本就是逆水行舟,不进则退。

如果你也有同样的困扰,别慌。

从现在开始,跟着我一起心态归零,利用碎片时间,来一次彻彻底底的基础扫盲

这一次,我们一起慢慢来,扎扎实实变强。

不搞花里胡哨的理论堆砌,只分享看得懂、用得上的前端干货,

咱们一起稳步积累,真正摆脱“面向搜索引擎写代码”的尴尬。


前言

无论你是刚学 JavaScript 的小白,还是已经写了几年代码的前端,只要在写后台管理系统,大概率都踩过 this 和箭头函数的坑。

这篇文章不讲特别玄学的底层原理,只回答三个问题:

  1. 日常写代码该怎么选?(普通函数 vs 箭头函数)
  2. 为什么这么选?
  3. 坑最容易出在哪里?

⬆ 返回目录


一、一个真实的报错场景

先看一段后台管理系统里常见的代码:

// 表格操作列有个「删除」按钮methods:{handleDelete(id){this.$confirm('确定删除吗?').then(()=>{this.deleteApi(id);// ❌ 报错:Cannot read property 'deleteApi' of undefined});}}

很多人会疑惑:我明明在 methods 里写的,this 怎么会是 undefined

问题在于:this 不是由「你在哪写的」决定的,而是由「谁在调用这个函数」决定的。$confirm().then() 里的回调,是 Promise 内部在调用,普通函数不会自动带上 Vue 实例的 this

如果把 .then() 里的回调改成箭头函数,就不会报错了。后面会详细说明原因。

ps·补充回调函数概念(供新手同学参考)
  • 非回调函数:定义后由你直接调用(fn()),执行时机由你决定;
  • 回调函数:把函数作为参数传递给另一个函数,由这个 “接收方函数” 在特定时机(比如异步操作完成、遍历完成)调用它。
// 1. 普通函数:自己定义、自己调用functionnormalFn(){ console.log("我是普通函数,直接调用就执行");}// 主动调用普通函数normalFn();// 输出:我是普通函数,直接调用就执行// 2. 回调函数:作为参数传递,由其他函数调用functioncallbackFn(){ console.log("我是回调函数,由forEach调用");}// forEach是接收回调的主函数,它会遍历数组时调用回调函数[1,2,3].forEach(callbackFn);// 输出3次:我是回调函数,由forEach调用// 更常见的写法:匿名回调函数(简化版)[1,2,3].forEach(function(item){ console.log("遍历到的元素:", item);// 异步/同步场景都常用});// 异步回调(典型场景:定时器)setTimeout(function(){ console.log("1秒后执行的回调函数");// 1秒后才执行,时机由setTimeout决定},1000);

⬆ 返回目录


二、基础扫盲:this 到底是谁决定的

核心结论 this 由「调用方式」决定,而不是由「定义位置」决定。

调用方式this 指向典型场景
作为对象方法调用该对象obj.fn() → this 是 obj
直接调用 fn()严格模式:undefined;非严格:window孤立的函数调用
new 调用新创建的对象new Foo()
call/apply/bind传入的第一个参数显式指定 this
作为回调传入谁调就指向谁,通常丢 thissetTimeout(fn)、Promise.then(fn)

关键点:当函数被当作回调传给别人时,谁调这个函数,this 就由谁决定。 比如 setTimeout(fn) 里,是浏览器在调 fn,所以 this 通常是 windowundefined,而不是你组件里的 this

⬆ 返回目录


三、箭头函数 vs 普通函数:本质区别

对比项普通函数箭头函数
this有属于自己的 this,由调用方式决定没有自己的 this,使用外层作用域的 this
arguments没有(可用 ...args 替代)
能否 new可以不可以
能否作为构造函数可以不可以

⬆ 返回目录

3.1. this 的区别(案例说明)

普通函数的 this 由调用方式决定,而箭头函数没有自己的 this,会 “继承” 外层作用域的 this

// 案例1:对象方法中的 thisconst person ={name:"张三",// 普通函数作为对象方法sayNameNormal:function(){ console.log("普通函数 this:",this.name);// this 指向调用者 person},// 箭头函数作为对象方法sayNameArrow:()=>{ console.log("箭头函数 this:",this.name);// this 指向外层(全局window),没有name属性}}; person.sayNameNormal();// 输出:普通函数 this: 张三 person.sayNameArrow();// 输出:箭头函数 this: undefined// 案例2:嵌套函数中的 thisconst obj ={num:10,fn:function(){// 普通嵌套函数:this 指向全局(非严格模式)setTimeout(function(){ console.log("普通嵌套函数 this.num:",this.num);// undefined},0);// 箭头嵌套函数:this 继承外层 fn 的 this(即obj)setTimeout(()=>{ console.log("箭头嵌套函数 this.num:",this.num);// 10},0);}}; obj.fn();
解释:
  • 普通函数 sayNameNormalperson 调用,this 就指向 person
  • 箭头函数 sayNameArrow 没有自己的 this,直接用外层(全局)的 this,而全局 thiswindow)没有 name 属性,所以是 undefined
  • 嵌套场景中,箭头函数能 “捕获” 外层函数的 this,这也是实际开发中箭头函数最常用的场景(避免手动绑定 this)。

⬆ 返回目录

3.2. arguments 的区别(案例说明)

普通函数有 arguments 对象(存储传入的所有参数),箭头函数没有,需用剩余参数 ...args 替代。

// 普通函数:有 argumentsfunctionnormalFn(){ console.log("普通函数 arguments:", arguments);// 输出传入的参数集合 console.log("第一个参数:", arguments[0]);}// 箭头函数:无 arguments,用 ...args 替代constarrowFn=(...args)=>{// console.log(arguments); // 直接用会报错:ReferenceError: arguments is not defined console.log("箭头函数 args:", args);// 数组形式存储参数 console.log("第一个参数:", args[0]);};normalFn(10,20,30);// 输出:普通函数 arguments: [Arguments] { '0': 10, '1': 20, '2': 30 }// 输出:第一个参数: 10arrowFn(10,20,30);// 输出:箭头函数 args: [ 10, 20, 30 ]// 输出:第一个参数: 10
解释:
  • arguments 是类数组对象,只能在普通函数中使用;
  • 箭头函数要获取所有参数,必须用 ES6 的剩余参数 ...argsargs 是真正的数组,还能使用 map/filter 等数组方法,比 arguments 更灵活。

⬆ 返回目录

3.3. 能否 new / 作为构造函数(案例说明)

普通函数可以用 new 调用(作为构造函数),箭头函数不行,强行 new 会报错。

// 普通函数:可作为构造函数functionPerson(name){this.name = name;}const p1 =newPerson("李四"); console.log("普通函数构造的实例:", p1.name);// 李四// 箭头函数:不能作为构造函数constArrowPerson=(name)=>{this.name = name;};try{const p2 =newArrowPerson("王五");// 强行new会报错}catch(e){ console.log("箭头函数 new 报错:", e.message);// ArrowPerson is not a constructor}
解释:
  • 构造函数的核心是 new 操作会创建新对象,并把函数的 this 绑定到这个新对象;
  • 箭头函数没有自己的 this,也没有 prototype 属性(构造函数的必要条件),所以无法作为构造函数使用。
小结:
  1. this 指向:普通函数的 this 由调用方式决定,箭头函数继承外层作用域的 this(无自身 this);
  2. 参数获取:普通函数用 arguments,箭头函数无 arguments,需用 ...args 剩余参数;
  3. 构造函数能力:普通函数可 new 作为构造函数,箭头函数不行,强行 new 会报错。

这三个区别是箭头函数和普通函数最核心的差异,其中 this 指向的区别是实际开发中最常遇到、也最需要注意的点。

⬆ 返回目录


四、后台项目里最容易写错的 5 种场景

4.1 场景 1:Element UI / Ant Design 表格里的回调

 // ❌ 错误写法:箭头函数里加 this.,会从 window 找方法,导致 this 失效 <el-table-columnlabel="操作"><templateslot-scope="scope"><el-button@click="() => this.handleEdit(scope.row)">编辑</el-button></template></el-table-column> // ✅ 最优写法:直接传方法引用,Vue 自动绑定组件实例的 this <el-button@click="handleEdit(scope.row)">编辑</el-button> // ⚠️ 能运行但不推荐:箭头函数里不加 this.(Vue 会映射到组件方法),但多一层包装无意义 <el-button@click="(row) => handleEdit(row)">编辑</el-button>

原因:

  • 模板中的事件绑定,Vue 会自动将方法的 this 绑定到组件实例上(而非 window)。

错误写法:箭头函数的 this 固定指向全局上下文(window/undefined),this.handleEdit 会从 window 查找方法(找不到),且方法内部的 this 也会失效;

  • 直接写方法名:Vue 会把模板里的 handleEdit 隐式映射到「组件实例的 methods」,并自动绑定组件的 this,是最安全高效的方式。

结论: 模板事件绑定优先直接写 方法名(参数)(最优解);尽量不要用箭头函数包装(避免多余的函数创建 + 踩 this 坑);若因特殊场景非要用箭头函数,需去掉 this.(如 (row) => handleEdit(row)),但这种写法无必要,仅作为兜底参考。

⬆ 返回目录


4.2 场景 2:Promise / async 里的 this

// ❌ 错误:.then 里用普通函数,this 丢失handleSubmit(){this.validateForm().then(function(res){this.submitForm();// this 是 undefined!});}// ✅ 正确:用箭头函数,继承外层的 thishandleSubmit(){this.validateForm().then((res)=>{this.submitForm();// this 正确指向组件实例});}

原因:.then() 的回调是 Promise 内部调用的,普通函数不会自动绑定组件 this。用箭头函数可以继承 handleSubmit 所在作用域的 this,即组件实例。

结论:Promiseasync/awaitsetTimeout 等异步回调里,需要访问组件/外层 this 时,用箭头函数。

⬆ 返回目录


4.3 场景 3:对象方法 / API 封装

// ❌ 错误:箭头函数作为对象方法,this 指向外层(window)const api ={baseUrl:'/api',getList:()=>{return axios.get(this.baseUrl +'/list');// this.baseUrl 是 undefined!}};// ✅ 正确:用普通函数const api ={baseUrl:'/api',getList(){return axios.get(this.baseUrl +'/list');}};

原因: 箭头函数没有自己的 this,会去外层找。这里的 getList 定义在对象字面量里,外层是全局,this 就是 window(或 undefined),自然拿不到 baseUrl

结论: 对象方法、Class 方法需要用到 this 时,用普通函数,不要用箭头函数。

⬆ 返回目录


4.4 场景 4:事件监听器(addEventListener)

// 场景:监听 window 滚动,组件销毁时需要移除监听// ❌ 错误:箭头函数每次都是新引用,无法正确 removeEventListenermounted(){ window.addEventListener('scroll',()=>this.handleScroll());},beforeDestroy(){ window.removeEventListener('scroll',()=>this.handleScroll());// 移除失败!引用不同}// ✅ 正确:保存同一个函数引用mounted(){this.boundHandleScroll =this.handleScroll.bind(this); window.addEventListener('scroll',this.boundHandleScroll);},beforeDestroy(){ window.removeEventListener('scroll',this.boundHandleScroll);}

原因:removeEventListener 必须传入和 addEventListener 时完全相同的函数引用。每次写 () => this.handleScroll() 都会生成新函数,所以无法正确移除。

结论: 需要手动移除监听时,用 bind 或普通函数,并把引用存到实例上,保证添加和移除用的是同一个函数。

⬆ 返回目录


4.5 场景 5:数组方法的回调(forEachmapfilter 等)

// 在 Vue 组件里methods:{processList(){const list =[1,2,3];// ❌ 错误:普通函数作为 forEach 回调,this 会丢 list.forEach(function(item){this.doSomething(item);// this 是 undefined});// ✅ 正确:箭头函数继承外层的 this list.forEach((item)=>{this.doSomething(item);});}}

原因:forEach 等方法的回调是由数组方法内部调用的,普通函数不会绑定组件 this。用箭头函数可以继承 processListthis

结论:forEachmapfilterreduce 等回调里需要访问外层 this 时,用箭头函数;不需要 this 时,两者都可以。

⬆ 返回目录


五、决策清单:什么时候用谁

可以按下面几条来选:

  1. 对象方法、Class 方法、构造函数 → 用普通函数。
  2. Promise、setTimeout、数组方法等回调里要访问外层 this → 用箭头函数。
  3. Vue 模板事件 → 直接写方法名,或 (arg) => this.method(arg),避免乱包箭头函数。
  4. 需要 arguments → 用普通函数,或箭头函数 + ...args
  5. addEventListener / removeEventListener → 用 bind 或保存同一引用,保证添加和移除是同一个函数。

⬆ 返回目录


六、一句话口诀

  • 普通函数:有「自己的」this,谁调我,this 就指向谁。
  • 箭头函数:没有「自己的」this,用的是「定义时所在作用域」的 this

因此,在需要「继承」外层 this 的场景(例如 PromisesetTimeout 回调),用箭头函数;在对象方法、构造函数等需要「自己的」this 的场景,用普通函数。需要「动态 this」用普通函数,需要「固定外层 this」用箭头函数。

⬆ 返回目录


总结

this 和箭头函数本身不复杂,容易出错的是「在错误场景选错写法」。后台项目里,最容易踩坑的就是:Promise 回调对象方法模板事件事件监听器这几处。记住「谁在调用」「外层 this 是谁」,选普通函数还是箭头函数就不容易错。

⬆ 返回目录

🔍 系列模块导航

📝 JS 基础语法与数据操作

一、《var/let/const:变量与作用域实战选型|JS 基础语法与数据操作篇》
二、《this、箭头函数与普通函数:前端实战避坑指南 | JS 基础语法与数据操作篇》
三、《对象解构赋值:接口数据解包 10 个实战写法|JS 基础语法与数据操作篇》
四、《map/filter/reduce:数组10个常用实战操作|JS 基础语法与数据操作篇》
五、《find/some/every/includes:数组查找与判断实战用法|JS 基础语法与数据操作篇》
六、《sort/localeCompare:对象数组排序与分组实战|JS 基础语法与数据操作篇》
七、《模板字符串 /split/join/ 正则:字符串处理实战|JS 基础语法与数据操作篇》
八、《Date/dayjs:日期时间处理实战|JS 基础语法与数据操作篇》
九、《try/catch/Promise:前端错误处理实战|JS 基础语法与数据操作篇》
十、《import/export:前端模块化实战|JS 基础语法与数据操作篇》

👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~

📚 系列总览

前端体系化学习完全体:基础 → 规范 → 架构 → 大厂面试
四套系列、百余篇高质量实战文,从入门到进阶,一站式补齐前端核心能力
  • 前端基础实战系列《前端基础实战:JS/TS与Vue体系化扫盲(47 篇完整目录 + 避坑)》
  • 前端规范实战系列:工程化编码规范 + API / 交互 / 组件统一标准(持续更新中)
  • 前端架构实战系列:聚焦工程化、性能优化、可维护架构、中后台体系设计(规划中)
  • 前端大厂面试系列:覆盖高频考点、手写题、项目深挖、简历与面试技巧(规划中)

每个系列完结后,都会整理成一篇完整导航文并附上直达链接,方便大家按顺序、体系化学习。

全套内容持续更新中,敬请期待~

⬆ 返回目录


学习本就是一场持久战,不需要急着一口吃成胖子。哪怕今天你只记住了一点点,这都是实打实的进步。

后续我还会继续用这种大白话、讲实战方式,带大家扫盲更多前端基础。

关注我,不迷路,咱们把那些曾经模糊的知识点,一个个彻底搞清楚。

如果你觉得这篇内容对你有帮助,不妨点赞+收藏,下次写代码卡壳时,拿出来翻一翻,比搜引擎更靠谱。

我是 Eugene,你的电子学友,我们下一篇干货见~

Read more

2026 GitHub 热门 Python 项目:AI 代理与数据工具精选

2026 GitHub 热门 Python 项目:AI 代理与数据工具精选

2026 年的 Python 生态正在被 AI 代理(AI Agent)和数据工程工具重新定义。本文精选 GitHub 上最具影响力的开源项目,涵盖 AI 代理框架、数据管道工具、向量数据库客户端等关键领域,附带代码示例与架构解析。 一、2026 Python 开源生态全景图 ┌─────────────────────────────────────────────────────────────────────┐ │ 2026 Python 开源热门方向 │ ├──────────────────┬──────────────────┬───────────────────────────────┤ │ AI 代理框架 │ 数据工具链 │ 基础设施与编排 │ ├──────────────────┼──────────────────┼───────────────────────────────┤ │ LangGraph │ Polars │ Dagster │ │ CrewAI │ DuckDB │ Prefect │ │ AutoGen │ ibis-project │

【Claude Code解惑】深度评测:Claude Code vs. GitHub Copilot CLI,谁才是终端之王?

【Claude Code解惑】深度评测:Claude Code vs. GitHub Copilot CLI,谁才是终端之王?

深度评测:Claude Code vs. GitHub Copilot CLI,谁才是终端之王? 目录 1. 引言与背景 2. 原理解释(深入浅出) 3. 10分钟快速上手(可复现) 4. 代码实现与工程要点 5. 应用场景与案例 6. 实验设计与结果分析 7. 性能分析与技术对比 8. 消融研究与可解释性 9. 可靠性、安全与合规 10. 工程化与生产部署 11. 常见问题与解决方案(FAQ) 12. 创新性与差异性 13. 局限性与开放挑战 14. 未来工作与路线图 15. 扩展阅读与资源 16. 图示与交互 17. 术语表与速查表 18. 互动与社区 0.

【资讯热点】2026 AI 编程新范式:从 Copilot 到 Agentic Coding 的效率革命

【资讯热点】2026 AI 编程新范式:从 Copilot 到 Agentic Coding 的效率革命

【资讯热点】2026 AI 编程新范式:从 Copilot 到 Agentic Coding 的效率革命 文章目录 * 【资讯热点】2026 AI 编程新范式:从 Copilot 到 Agentic Coding 的效率革命 * 一、AI编程的变革:从工具到智能伙伴(引言) * 二、Copilot的崛起与挑战:效率提升与局限性(发展现状) * 三、Agentic Coding:驱动未来编程的智能体(核心概念) * 四、Agentic Coding的工作流与应用场景(实战展望) * 五、挑战与机遇:拥抱AI编程新范式(展望与建议) * 六、总结:AI编程的未来已来(价值升华) * 七、下一期预告(系列引导) * 参考链接

从 99.8% 到 14.9%:Paperzz 降重 / 降 AIGC 实测,破解知网最新检测的实用指南

从 99.8% 到 14.9%:Paperzz 降重 / 降 AIGC 实测,破解知网最新检测的实用指南

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿paperzz - 降重/降AIGChttps://www.paperzz.cc/weight 当知网、维普再次升级 AIGC 检测机制,不少同学的论文初稿被打出 99.8% 的 AIGC 疑似度时,那种 “一夜回到解放前” 的焦虑,想必很多人都深有体会。传统的同义词替换、语序调整早已失效,单纯降重又容易让文本变得口语化、散文化。Paperzz 的 “降重 / 降 AIGC” 功能,正是在这样的背景下,成为了不少人应对学术检测的 “救命稻草”。本文将结合平台界面,为你深度拆解 Paperzz 如何通过 AI 技术与专业服务,帮你安全、高效地通过最新一轮学术检测。 一、检测升级:知网 AIGC