常规函数与箭头函数
098 Regular Functions vs. Arrow Functions(常规函数与箭头函数)笔记
一、核心主题
本章节聚焦 JavaScript 中常规函数与箭头函数的核心差异,重点围绕this关键字指向规则、arguments关键字可用性展开,结合实际代码案例解析常见陷阱,并给出不同场景下的函数选择建议,帮助开发者规避错误、正确运用两种函数。
二、箭头函数作为对象方法的陷阱
2.1 问题表现
当用箭头函数定义对象的方法时,无法正确访问对象自身的属性,会出现undefined或意外获取全局变量的情况。
2.2 代码案例
1 | // 定义包含箭头函数方法的对象 |
2.3 原理分析
- 箭头函数无自身
this:箭头函数不绑定自己的this,会继承父作用域的this。 - 对象字面量不创建作用域:
Jonas是对象字面量({}),并非代码块,不会生成新作用域,其内部的箭头函数greet的父作用域是全局作用域。 - 全局作用域的
this:浏览器环境中,全局作用域的this指向Window对象,因此箭头函数中的this最终指向Window。 - var 声明的副作用:用
var声明的全局变量会自动挂载到Window对象上,导致箭头函数误访问全局变量而非对象自身属性。
2.4 解决方案
永远不要用箭头函数作为对象的方法,应使用常规函数(函数表达式)定义对象方法,确保this指向调用方法的对象:
1 | const Jonas = { |
三、方法内部常规函数的this问题及解决办法
3.1 问题表现
在对象的常规方法内部定义另一个常规函数时,内部常规函数的this会指向undefined(严格模式下),导致无法访问外部方法的this(即对象自身)。
3.2 代码案例(问题场景)
1 | const Jonas = { |
3.3 原理分析
- 常规函数的
this绑定规则:常规函数的this指向调用者,若直接调用(无明确调用者,如isMillennial()),在严格模式下this为undefined,非严格模式下指向Window。 - 作用域隔离:方法内部的常规函数
isMillennial有自己的作用域,其this不继承外部方法calcAge的this(即 Jonas 对象)。
3.4 解决方案
方案 1:ES6 之前 —— 用变量保存外部this(传统方案)
通过在外部方法中定义变量(如self或that),保存外部的this(指向对象),内部函数通过作用域链访问该变量:
1 | const Jonas = { |
方案 2:ES6 之后 —— 用箭头函数(推荐方案)
利用箭头函数 “继承父作用域this” 的特性,将内部函数定义为箭头函数,使其this直接指向外部方法calcAge的this(即 Jonas 对象):
1 | const Jonas = { |
四、arguments关键字的可用性差异
4.1 核心规则
- 常规函数:可访问
arguments关键字,它是一个包含所有传入参数的类数组对象(有索引和length属性,但无数组方法如forEach),支持接收多于定义参数数量的参数。 - 箭头函数:不可访问
arguments关键字,调用时会报错 “arguments is not defined”。
4.2 代码案例(常规函数)
1 | // 常规函数表达式:计算所有传入参数的和 |
4.3 代码案例(箭头函数,报错场景)
javascript
1 | // 箭头函数:试图访问arguments |
4.4 现代替代方案
arguments在现代 JavaScript 中重要性下降,推荐用剩余参数(...rest) 替代,剩余参数是真正的数组,支持所有数组方法,且箭头函数和常规函数都可使用:
javascript
1 | // 常规函数用剩余参数 |
五、常规函数与箭头函数使用总结
5.1 核心差异对比表
| 特性 | 常规函数(Regular Functions) | 箭头函数(Arrow Functions) |
|---|---|---|
this绑定 |
绑定调用者(谁调用指向谁) | 无自身this,继承父作用域this |
arguments关键字 |
可访问(类数组对象) | 不可访问(报错) |
| 构造函数用法 | 可作为构造函数(用new创建实例) |
不可作为构造函数(用new报错) |
prototype属性 |
有prototype属性 |
无prototype属性 |
| 简写形式 | 无(需写function关键字) |
有(省略function、return和大括号,单参数可省括号) |
5.2 场景化选择建议
-
对象方法:用常规函数(确保
this指向对象自身),禁止用箭头函数。✅ 正确:
greet: function() {}或greet() {}(ES6 对象方法简写)❌ 错误:
greet: () => {} -
方法内部嵌套函数:用箭头函数(继承外部
this,无需额外变量保存),或用常规函数 +self(传统方案)。✅ 推荐:
const innerFn = () => {}✅ 兼容:
const self = this; function innerFn() {} -
回调函数(如
setTimeout、数组方法):优先用箭头函数(避免this指向丢失)。案例:
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const Jonas = {
name: "Jonas",
delayGreet: function () {
// 箭头函数作为setTimeout回调,this指向Jonas
setTimeout(() => {
console.log(`嘿,${this.name}`);
}, 1000);
// 若用常规函数,this指向Window(错误)
setTimeout(function () {
console.log(`嘿,${this.name}`); // 输出“嘿,undefined”
}, 2000);
},
};
Jonas.delayGreet(); -
需要访问多参数:用常规函数(
arguments) 或剩余参数(...rest)(推荐,箭头函数也可用)。✅ 现代方案:
function fn(...args) {}或const fn = (...args) => {} -
构造函数:用常规函数(箭头函数无
prototype,无法创建实例)。✅ 正确:
function Person(name) { this.name = name; }❌ 错误:
const Person = (name) => { this.name = name; }(用new Person()报错)


