箭头函数不能 new,不是语法层面"禁止你写",而是它从底层就缺少构造函数需要的能力。
先看 new 到底做了什么
new Foo() 大致会执行这几步:
- 创建一个空对象;
- 把这个空对象的
__proto__指向Foo.prototype; - 把
this绑定到这个新对象; - 执行函数体;
- 如果函数没有返回对象,就返回这个新对象。
所以普通函数能当构造函数,依赖三个东西:
- 有
[[Construct]]内部方法; - 有
prototype; this可以在调用时被绑定到新对象。
箭头函数缺了什么?
1. 没有 [[Construct]]
普通函数同时有 [[Call]] 和 [[Construct]],所以既能普通调用,也能 new 调用。
箭头函数只有 [[Call]],没有 [[Construct]]。
所以:
js
编辑
ini
const A = () => {};
new A(); // TypeError: A is not a constructor
引擎一看到 new 后面是箭头函数,就直接报错。
2. 没有 prototype
js
编辑
javascript
function Foo() {}
console.log(Foo.prototype); // {}
const Bar = () => {};
console.log(Bar.prototype); // undefined
new 需要把实例挂到 Foo.prototype 上形成原型链。箭头函数没有 prototype,这一步根本没法做。
3. this 是词法绑定,不能被 new 改写
普通函数作为构造函数时,this 会指向新创建的对象:
js
编辑
javascript
function Person(name) {
this.name = name; // this 指向 new 出来的实例
}
但箭头函数的 this 在定义时就从外层作用域捕获了,之后无论怎么调用都不会变。
js
编辑
ini
const Person = (name) => {
this.name = name; // this 不是新对象,而是外层 this
};
这就和 new 的语义冲突了:new 要求 this 指向新实例,而箭头函数不允许 this 被重新绑定。
一句话理解
箭头函数被设计成"只负责执行",不负责"创建对象"。 它没有 [[Construct]],没有 prototype,this 也不能被 new 改写,所以天然不能作为构造函数。
这也和前面类组件里 handleClick = () => {} 是一致的:它只是在构造函数执行时,把箭头函数赋给实例属性,并不是 new 这个箭头函数。