0x00 TL;DR

因为 Lexical this 导致没有 [[Construct]],所以不能 new

0x01 详细版本

如果去查一下 ECMA spec,其实可以看到如下的解释:

A function object is an object that supports the [[Call]] internal method. A constructor is an object that supports the [[Construct]] internal method. Every object that supports [[Construct]] must support [[Call]]; that is, every constructor must be a function object. Therefore, a constructor may also be referred to as a constructor function or constructor function object.

所以想要对某个对象使用 new,就得确保该对象具有 [[Construct]] 这个内部方法。而 ArrowFunction 没有 [[Construct]]

再多查一点的话,可以在 14.2.17 这一节看到如下的注解:

An ArrowFunction does not define local bindings for arguments, super, this, or new.target. Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment.

再多查一点的话,可以找到最终通过的 proposal:https://tc39wiki.calculist.org/es6/arrow-functions/

The goal of Arrow Functions is to address and resolve several common pain points of traditional Function Expression:

  • Lexical this binding;
  • Shorter syntactical form (() => {} vs. function () {})

Lexical this matches the dominant cohort measured by Kevin Smith (see the BTF Measurements thread that either does not use this or wants it lexically bound.

  • Best results after modifying subject code to use method definition shorthand and only then scanning for function.
  • From lexical this it follows that arrow functions are not constructors (no .prototype or [[Construct]]).

再多查一点的话,你可以在 2011 年的一次讨论里找到这个设计的来源:https://mail.mozilla.org/pipermail/es-discuss/2012-March/021953.html

We do not want to delegate to a target function that can [[Construct]], because there is no such target function -- we're not trying to sugar .bind on a full function. That is too expensive and general (no pre-args, no full function under the hood).

Lexical-only this binding means no [[Construct]] and no .prototype for arrow functions. I'm ok with this.


考虑典型的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
constructor() {
this.attr = 0;
}
}

const a = new A();

// or

function A() {
this.attr = 0;
}

const a = new A();

在这两种构造实例的方法中,this 指向的都是正在被操作的变量 a。 但是 arrow function 在还是个草案的时候就只计划支持 Lexical this,因此它的函数体中的 this 不会指向正在被操作的变量 a,无法修改赋值表达式的左值,因此就算 ArrowFunction[[Construct]] 内部方法也无法用于构造新对象。

来源:https://blog.jiejiss.com/