构造函数使用 ES6 速记符号表现不同 [英] Constructor behaving differently using ES6 shorthand notation

查看:13
本文介绍了构造函数使用 ES6 速记符号表现不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ES6 引入了速记符号 用函数和属性初始化对象.

//ES6 速记符号常量对象 1 = {一(二){console.log("ES6: obj1");}};//ES5var obj2 = {a: 函数 a(b) {console.log("ES5: obj2");}};obj2.a();obj1.a();新的 obj2.a();new obj1.a();

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

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

解决方案

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

我们将从 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一个参数,对象.让我们看看DefineMethod - 这是我们需要的:

<块引用>

带参数对象和可选参数函数Prototype.

<小时>

  1. 如果 functionPrototype 作为参数传递,让 kindNormal;否则让 kind 成为 Method.
  2. closure 成为 FunctionCreate(kind, [截断更多参数]).

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

<块引用>

  1. 如果kind不是Normal,让allocKind成为非构造函数".
  2. 否则,让 allocKind 成为 normal".
  3. 设 F 为 FunctionAllocate([截取的其他参数], allocKind).

现在我们越来越近了!我们只需要看看 FunctionAllocate 的作用allocKind(按照上述步骤是 non-constructor"),这就是为函数提供其所有内部方法等的原因.

<块引用>

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

<小时>

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

<小时>

  1. 如果 needsConstructtrue,则

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

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

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

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

<块引用>

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

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

ES6 introduced a shorthand notation to initialize objects with functions and properties.

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

However, these different notations behave differently, as you can see. If I do new obj1.a() in the browser (tested Chrome and Firefox), I get a TypeError: obj1.a is not a constructor. new obj2.a() behaves completely normally.

What happens here? Does anyone have an explanation, and/or links to documentation/specification?

解决方案

The specification isn't very direct about explaining this, but we can follow a short chain..

We'll start at EvaluateNew, since that's the behaviour we're wondering about. Step 7 is clearly the one we're looking for here:

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

So IsConstructor is where we need to look next.

Both the summary and the steps describe this:

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.

So, judging by the looks of it, our obj1.a doesn't have a [[Construct]] internal method. Let's look for where it says that it shouldn't have one..

Here's what we're looking for, PropertyDefinitionEvaluation. The first step is useful here:

Let methodDef be DefineMethod of MethodDefinition with argument object.

That calls DefineMethod with just one argument, object. Let's look at DefineMethod - here's what we need:

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]).

Since functionPrototype was not passed as a parameter, the kind is Method. Let's look at what FunctionCreate does with that:

  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).

Now we're getting close! We just need to look at FunctionAllocate does with allocKind (which is "non-constructor" as per the above steps), which is what gives a function all of its internal methods and such.

  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".

Finally! If we go through the relevant steps, we can see since functionKind isn't "normal", needsConstruct becomes false, and so a [[Construct]] internal method is never assigned! Then IsConstructor sees that and returns false, and so EvaluateNew fails.

MDN describes this behaviour very simply:

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

..but now you know how they aren't constructors, officially.

这篇关于构造函数使用 ES6 速记符号表现不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆