使用ES6速记符号的构造函数行为不同 [英] Constructor behaving differently using ES6 shorthand notation
问题描述
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显然是我们正在寻找的:
- 如果IsConstructor 构造函数)是 false ,引发 TypeError 异常。
所以 IsConstructor 是我们需要看下的地方。
总结和步骤都描述了这一点:
抽象操作IsConstructor确定参数是否是具有[[Construct]]内部方法的函数对象
- 如果Type(参数)不是Object,返回 false 。
- 如果参数具有[[Construct]]内部方法,请返回 true 。
- 返回 false 。
所以,根据它的外观,我们的 obj1.a
不有一个[[构造]]内部方法。让我们来看看它不应该有一个..
这是我们要找的, PropertyDefinitionEvaluation 。第一步在这里很有用:
让methodDef定义MethodDefinition的方法与参数对象
调用 DefineMethod 只有一个参数对象。我们来看DefineMethod - 这是我们需要的:
使用参数对象和可选参数functionPrototype。
- 如果将 functionPrototype 作为参数传递, em> be
正常
;否则让 为方法
。
- 让关闭为FunctionCreate
由于函数原型被 作为参数传递,类型为方法
。让我们来看看 FunctionCreate 与之相关的内容: p>
- 如果 不是
正常
,let allocKind 为非构造函数
。
- 否则,让 allocKind 为
normal
。
- 让F为FunctionAllocate( [其他参数被剪切]
现在我们越来越近了!我们只需要查看功能分配与 allocKind (它是非构造函数
按照上述步骤),这是一个函数所有的内部方法等。 p>
- 如果 functionKind 是
,let needsConstruct be true 。
- 否则,let needsConstruct
- 让 F 成为新创建的ECMAScript函数对象,其内部插槽位于表27 。所有这些内部插槽都被初始化为未定义。
如果 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:
- 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.
- If Type(argument) is not Object, return false.
- If argument has a [[Construct]] internal method, return true.
- 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.
- If functionPrototype was passed as a parameter, let kind be
Normal
; otherwise let kind beMethod
.- 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:
- If kind is not
Normal
, let allocKind be"non-constructor"
.- Else, let allocKind be
"normal"
.- 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.
- If functionKind is
"normal"
, let needsConstruct be true.- Else, let needsConstruct be false.
- 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.
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屋!