简体   繁体   English

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

[英]Constructor behaving differently using ES6 shorthand notation

ES6 introduced a shorthand notation to initialize objects with functions and properties. ES6引入了一种简写符号来初始化具有函数和属性的对象。

 // 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 obj1.a() (测试过Chrome和Firefox),我会得到一个TypeError: obj1.a is not a constructor new obj2.a() behaves completely normally. new obj2.a()表现完全正常。

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. 我们将从EvaluateNew开始,因为这是我们想知道的行为。 Step 7 is clearly the one we're looking for here: 第7步显然是我们在这里寻找的那个:

  1. If IsConstructor( constructor ) is false , throw a TypeError exception. 如果IsConstructor( 构造函数 )为false ,则抛出TypeError异常。

So IsConstructor is where we need to look next. 所以IsConstructor是我们接下来要看的地方。

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. 抽象操作IsConstructor确定参数 (必须是ECMAScript语言值)是否是具有[[Construct]]内部方法的函数对象。


  1. If Type( argument ) is not Object, return false . 如果Type( 参数 )不是Object,则返回false
  2. If argument has a [[Construct]] internal method, return true . 如果参数有[[Construct]]内部方法,则返回true
  3. Return false . 返回false

So, judging by the looks of it, our obj1.a doesn't have a [[Construct]] internal method. 因此,根据它的外观来判断,我们的obj1.a没有[[Construct]]内部方法。 Let's look for where it says that it shouldn't have one.. 让我们来看看它不应该有一个......

Here's what we're looking for, PropertyDefinitionEvaluation . 这是我们正在寻找的东西, PropertyDefinitionEvaluation The first step is useful here: 第一步在这里很有用:

Let methodDef be DefineMethod of MethodDefinition with argument object . 让methodDef成为MethodDefinition的DefineMethod with argument object

That calls DefineMethod with just one argument, object . 这只使用一个参数object来调用DefineMethod Let's look at DefineMethod - here's what we need: 让我们看一下DefineMethod - 这就是我们需要的:

With parameters object and optional parameter functionPrototype. 带参数对象和可选参数functionPrototype。


  1. If functionPrototype was passed as a parameter, let kind be Normal ; 如果functionPrototype作为参数传递,则将kind设为Normal ; otherwise let kind be Method . 否则请善待 Method
  2. Let closure be FunctionCreate(kind, [more arguments snipped] ). 闭包为FunctionCreate(kind, [更多参数剪断] )。

Since functionPrototype was not passed as a parameter, the kind is Method . 由于functionPrototype 作为参数传递,因此类型为Method Let's look at what FunctionCreate does with that: 让我们看一下FunctionCreate对它的作用:

  1. If kind is not Normal , let allocKind be "non-constructor" . 如果kind不是Normal ,那么让allocKind成为"non-constructor"
  2. Else, let allocKind be "normal" . 否则,让allocKind "normal"
  3. Let F be FunctionAllocate( [other arguments snipped] , allocKind ). 设F为FunctionAllocate( [其他参数 剪切 ]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. 我们只需要看看FunctionAllocateallocKind的影响 (按照上面的步骤是"non-constructor" ),这就是函数的所有内部方法等等。

  1. If functionKind is "normal" , let needsConstruct be true . 如果functionKind"normal" ,请让needsConstructtrue
  2. Else, let needsConstruct be false . 否则,让needsConstruct

  1. Let F be a newly created ECMAScript function object with the internal slots listed in Table 27 . F是新创建的ECMAScript函数对象,其中内部插槽列于表27中 All of those internal slots are initialized to undefined . 所有这些内部插槽都初始化为未定义

  1. If needsConstruct is true , then 如果needsConstructtrue ,那么

    a. 一个。 Set F 's [[Construct]] internal method to the definition specified in 9.2.2. F的[[Construct]]内部方法设置为9.2.2中指定的定义。

    b. Set the [[ConstructorKind]] internal slot of F to "base" . F的[[ConstructorKind]]内部插槽设置为"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! 如果我们通过相关步骤,我们可以看到,因为functionKind不是"normal"needsConstruct变为false ,所以永远不会分配[[Construct]]内部方法! Then IsConstructor sees that and returns false, and so EvaluateNew fails. 然后IsConstructor看到并返回false,因此EvaluateNew失败。

MDN describes this behaviour very simply: MDN非常简单地描述了这种行为:

All method definitions are not constructors and will throw a TypeError if you try to instantiate them. 所有方法定义都不是构造函数,如果您尝试实例化它们,则会抛出TypeError。

..but now you know how they aren't constructors, officially. ..但现在你知道他们是如何构造不正式。

Methods declared using this syntax are not intended to be constructable 使用此语法声明的方法不可构造

Reference here 参考这里

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

MM: three reasons for this: MM:三个原因:

  • 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!! 要冻结一个类,我必须冻结原型上方法的.prototype!

and

AWB: suggestion: concise methods should be the same for both classes and object literals AWB:建议:对于类和对象文字,简明的方法应该是相同的

  • strictness 严格
  • enumerability enumerability
  • constructability 施工性
  • attributes 属性

That's how both class methods and object methods became non-constructable 这就是类方法和对象方法变得不可构造的方式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM