构造函数使用 ES6 shorthand 表示法表现不同

Constructor behaving differently using ES6 shorthand notation

ES6 引入了shorthand notation 来初始化具有函数和属性的对象。

// ES6 shorthand notation
const obj1 = {
    a(b) {
        console.log("ES6: obj1");
    }
};

// ES5
var obj2 = {
    a: function a(b) {
        console.log("ES5: obj2");
    }
};

obj2.a();
obj1.a();

new obj2.a();
new obj1.a();

但是,如您所见,这些不同的表示法表现不同。如果我在浏览器中执行 new obj1.a()(已测试 Chrome 和 Firefox),我会得到 TypeError: obj1.a is not a constructornew obj2.a() 表现完全正常。

这里发生了什么?有人有解释吗,and/or 链接到 documentation/specification?

使用此语法声明的方法不可构造

Reference here

specification 解释得不是很直接,但我们可以遵循一个短链..

我们将从 EvaluateNew 开始,因为这是我们想知道的行为。第 7 步显然是我们在这里寻找的步骤:

  1. If IsConstructor(constructor) is false, throw a TypeError exception.

所以 IsConstructor 是我们下一步需要看的地方。

摘要和步骤都描述了这一点:

The abstract operation IsConstructor determines if argument, which must be an ECMAScript language value, is a function object with a [[Construct]] internal method.


  1. If Type(argument) is not Object, return false.
  2. If argument has a [[Construct]] internal method, return true.
  3. Return false.

所以,从表面上看,我们的 obj1.a 没有 [[Construct]] 内部方法。让我们看看它说它不应该有的地方..

这就是我们要找的东西,PropertyDefinitionEvaluation。第一步在这里很有用:

Let methodDef be DefineMethod of MethodDefinition with argument object.

调用 DefineMethod 只有一个参数,object。让我们看看 DefineMethod - 这是我们需要的:

With parameters object and optional parameter functionPrototype.


  1. If functionPrototype was passed as a parameter, let kind be Normal; otherwise let kind be Method.
  2. Let closure be FunctionCreate(kind, [more arguments snipped]).

由于functionPrototype 不是作为参数传递,种类是Method。让我们看看 FunctionCreate 做了什么:

  1. If kind is not Normal, let allocKind be "non-constructor".
  2. Else, let allocKind be "normal".
  3. Let F be FunctionAllocate([other arguments snipped], allocKind).

现在我们快到了!我们只需要看看 FunctionAllocateallocKind 的关系(按照上述步骤是 "non-constructor" ),这就是赋予函数所有内部方法的原因等等。

  1. If functionKind is "normal", let needsConstruct be true.
  2. Else, let needsConstruct be false.

  1. Let F be a newly created ECMAScript function object with the internal slots listed in Table 27. All of those internal slots are initialized to undefined.

  1. If needsConstruct is true, then

    a. Set F's [[Construct]] internal method to the definition specified in 9.2.2.

    b. Set the [[ConstructorKind]] internal slot of F to "base".

终于!如果我们完成相关步骤,我们可以看到因为 functionKind 不是 "normal"needsConstruct 变成 false ,所以 [[Construct]] 内部方法永远不会被赋值!然后 IsConstructor 发现 returns 错误,因此 EvaluateNew 失败。

MDN 非常简单地描述了这种行为:

All method definitions are not constructors and will throw a TypeError if you try to instantiate them.

..但现在你知道如何他们不是构造函数,正式的。

原来的讨论似乎发生在这里: https://github.com/rwaldron/tc39-notes/blob/master/es6/2012-07/july-26.md

MM: three reasons for this:

  • precedent in builtins
  • using a method as a constructor is generally nonsense
  • to freeze a class, I have to freeze the .prototype of the methods on the prototype!!

AWB: suggestion: concise methods should be the same for both classes and object literals

  • strictness
  • enumerability
  • constructability
  • attributes

这就是 class 方法和对象方法都变得不可构造的原因