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

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

问题描述

ES6引入了速记符号< a>使用函数和属性初始化对象



  // ES6 shorthand notationconst obj1 = {a(b){console.log(ES6:obj1); }}; // ES5var 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不是构造函数 new obj2.a()行为完全正常。



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

解决方案

规范对于解释这一点不是很直接,但我们可以跟随一条短链。



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



  1. 如果IsConstructor 构造函数)是 false ,引发 TypeError 异常。




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



总结和步骤都描述了这一点:


抽象操作IsConstructor确定参数是否是具有[[Construct]]内部方法的函数对象







  1. 如果Type(参数)不是Object,返回 false

  2. 如果参数具有[[Construct]]内部方法,请返回 true

  3. 返回 false


所以,根据它的外观,我们的 obj1.a 不有一个[[构造]]内部方法。让我们来看看它不应该有一个..



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


让methodDef定义MethodDefinition的方法与参数对象

调用 DefineMethod 只有一个参数对象。我们来看DefineMethod - 这是我们需要的:


使用参数对象和可选参数functionPrototype。







  1. 如果将 functionPrototype 作为参数传递, em> be 正常;否则让 方法

  2. 关闭为FunctionCreate


由于函数原型 作为参数传递,类型为方法。让我们来看看 FunctionCreate 与之相关的内容: p>



  1. 如果 不是正常,let allocKind 非构造函数

  2. 否则,让 allocKind normal

  3. 让F为FunctionAllocate( [其他参数被剪切]


现在我们越来越近了!我们只需要查看功能分配 allocKind (它是非构造函数按照上述步骤),这是一个函数所有的内部方法等。 p>



  1. 如果 functionKind ,let needsConstruct be true

  2. 否则,let needsConstruct







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







  1. 如果 needConstruct true ,那么



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



    b。将 F 的[[ConstructorKind]]内部插槽设置为base



最后!如果我们通过相关步骤,我们可以看到,由于 functionKind 不是normal strong> false ,所以一个[[构造]]内部方法从未被分配!然后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天全站免登陆