ES6中箭头函数的作用
文章目录
- 1. JavaScript 函数的“双重身份”
- 2. ES6 的新解法:箭头函数
- 3. 为什么要消除二义性?
- 4. 顺带的特性变化
- 5. 总结
1. JavaScript 函数的“双重身份”
在 ES6 之前,JavaScript 中的 函数是一种“多面手”:
- 你可以把他当做 普通函数 调用,用来执行一段逻辑。
- 你也可以把它当做 构造函数 调用,用 new 创建一个新的实例对象。
这种设计非常灵活,但也带来了一个问题—— 二义性。
来看一个例子:
function Person(name) {this.name = name;
}// 作为构造器使用
const p1 = new Person('HopeBearer');
console.log(p1.name); // HopeBearer// 作为普通函数使用Person('HopeBearer');
console.log(globalThis.name); // HopeBearer(非严格模式)
同一段代码,既可以构造对象,也可以作为普通函数运行。从语法层面上,你很难一眼看出这个函数的意图。
二义性带来的问题:
- 可读性差: 读代码的人需要结合上下文,才能判断这个函数是不是要被 new。
- 容易出错: 调用构造函数时忘写 new,可能会导致全局对象被污染(严格模式下是 TypeError)。
注:在 ES6 之前一般是通过约定将其二义分开,比如小写字母开头的就是普通函数,大写字母开头的就是构造函数。
2. ES6 的新解法:箭头函数
ES6 引入了箭头函数,它直接砍掉了“构造函数”这条分支,让函数更单一:
const Person = () => {this.name = name;
}new Person('HopeBearer');
// TypeError: Person is not a constructorconsole.log(Person.prototype); // undefined
箭头函数从语义上直接告诉我们:
这是一条指令序列,与面向对象的实例化无关。
那么它就没有了面向对象的特性:
- 不能用 new 调用(不是构造函数)。
- 没有自己的 this (继承外层作用域的 this)。
- 没有 prototype 属性(因为不能构造实例)。
也就是说:
- 不具备封装能力。
- 完全不能继承,也不能被继承。
- 没有类的多态能力。
3. 为什么要消除二义性?
我认为的原因主要是:
1.提升代码可读性和意图表达。 消除二义性后,函数的角色明确(要么纯逻辑执行,要么专门构造实例),代码更“说人话”,语义更清晰。
2. 减少调用错误。 消除二义性后,比如箭头函数不能被 new,直接避免了调用构造时漏写 new 的问题,程序更加健壮。
3. 符合单一职责原则。 设计语言特性时,单一职责原则(SRP)是重要原则:一个实体只负责一个功能。传统函数的双重身份违背了 SRP,既是构造器又是普通函数。
4. 顺带的特性变化
虽然很多文章会从 this 绑定讲起,但这些其实是消除二义性后的自然结果:
特性 | 普通函数 (function ) | 箭头函数 (()=>{} ) |
---|---|---|
调用方式 | 普通调用 / new 构造 | 只能普通调用 |
this | 调用时动态绑定 | 定义时静态绑定(外层作用域) |
prototype | 有 | undefined |
arguments | 有 | 没有(用剩余参数代替) |
generator 支持 | 可以 | 不可以 |
其中,this 静态绑定和没有 arguments,正好让箭头函数在回调、定时器、数组方法等场景中写起来更简洁。
5. 总结
箭头函数的出现,不只是为了写得短一点,而是从语言设计的角度,让函数的角色更加单一化:
-
普通函数:既能构造对象,也能执行逻辑(双重身份)。
-
箭头函数:只能执行逻辑,与构造完全无关。
在这个基础上,this 静态绑定、没有 prototype 等特性成为了自然的设计延伸。
所以,如果你的函数只是一个动作的集合,不涉及面向对象构造,箭头函数就是更语义化、更安全的选择。