【问题标题】:Constructor behaving differently using ES6 shorthand notation构造函数使用 ES6 速记符号表现不同
【发布时间】:2017-05-02 18:21:45
【问题描述】:

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();

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

这里发生了什么?有没有人有解释和/或文档/规范的链接?

【问题讨论】:

  • 方法(在类或对象字面量中使用方法定义)和箭头函数不能与new 一起使用。为此,您必须使用老式的 functionclass 构造函数。
  • 在 ES6 之前,函数和构造函数都混在一起了。 ES6 试图区分它们。

标签: javascript methods ecmascript-6 shorthand


【解决方案1】:

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

Reference here

【讨论】:

  • 规范在哪里这么说的?
  • "所有方法定义都不是构造函数,如果您尝试实例化它们,将抛出 TypeError。"
  • MDN 不是规范。
  • 你是唯一一个使用“规范”这个词的朋友。
  • 不,OP也用过。
【解决方案2】:

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

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

  1. 如果 IsConstructor(constructor) 为 false,则抛出 TypeError 异常。

所以IsConstructor 是我们接下来需要关注的地方。

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

抽象操作 IsConstructor 确定 argument(必须是 ECMAScript 语言值)是否是具有 [[Construct]] 内部方法的函数对象。


  1. 如果 Type(argument) 不是 Object,则返回 false
  2. 如果 argument 有 [[Construct]] 内部方法,则返回 true
  3. 返回 false

所以,从它的外观来看,我们的obj1.a 没有 [[Construct]] 内部方法。让我们看看它说它不应该有一个..

这就是我们正在寻找的,PropertyDefinitionEvaluation。第一步在这里很有用:

令methodDef为MethodDefinition的DefineMethod,带参数object

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

带参数对象和可选参数functionPrototype。


  1. 如果 functionPrototype 作为参数传递,则让 kindNormal;否则让 kindMethod
  2. closure 为 FunctionCreate(kind, [more arguments snipped])。

由于functionPrototype没有作为参数传递,所以种类是Method。让我们看看FunctionCreate 对此做了什么:

  1. 如果 kind 不是 Normal,则让 allocKind"non-constructor"
  2. 否则,让 allocKind"normal"
  3. 令 F 为 FunctionAllocate([其他参数被剪断], allocKind)。

现在我们越来越近了!我们只需要查看FunctionAllocateallocKind 的关系(根据上述步骤,"non-constructor"),它为函数提供了所有内部方法等。

  1. 如果 functionKind"normal",则让 needsConstructtrue
  2. 否则,让 needsConstructfalse

  1. F 成为一个新创建的 ECMAScript 函数对象,其内部插槽列在 Table 27 中。所有这些内部槽都初始化为undefined

  1. 如果 needsConstructtrue,那么

    一个。将 F 的 [[Construct]] 内部方法设置为 9.2.2 中指定的定义。

    b.将F的[[ConstructorKind]]内部槽设为"base"

终于!如果我们通过相关步骤,我们可以看到,由于 functionKind 不是 "normal"needsConstruct 变为 false,因此 [[ Construct]] 内部方法永远不会被分配!然后 IsConstructor 看到并返回 false,因此 EvaluateNew 失败。

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

所有方法定义都不是构造函数,如果您尝试实例化它们,将会抛出 TypeError。

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

【讨论】:

    【解决方案3】:

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

    MM:三个原因:

    • 内置的先例
    • 使用方法作为构造函数通常是无稽之谈
    • 要冻结一个类,我必须冻结原型上的方法的.prototype!!

    AWB:建议:类和对象字面量的简洁方法应该相同

    • 严格
    • 可枚举性
    • 可施工性
    • 属性

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

    【讨论】:

      猜你喜欢
      • 2016-05-08
      • 2019-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-16
      • 2012-05-23
      • 1970-01-01
      • 2020-03-06
      相关资源
      最近更新 更多