今天在处理一个问题的时候无意中发现一个新的问题,对象内的简写方法不能用作构造函数使用,而属性赋值的匿名函数可以。
const obj1 = {
f:function () {
this.num = 0;
}
}
const obj2 = {
f() {
this.num = 0;
}
}
new obj1.f(); // f {num: 0}
new obj2.f(); // Uncaught TypeError: obj2.f is not a constructor
为此专门去和同学讨论和搜索了一下,后面放上是相关链接的 google 机翻,
总的结果就是,
未标识为构造函数的内置函数对象不实现 [[Construct]]
内部方法,
[[Construct]]
是我们使用new
或super
创建新对象时使用的东西,
只有类型的函数 Normal
才能构造和实现[[Construct]]
。
所以,只有 Normal
类型的函数(也就是用 function
关键字构造的函数)是可作为构造器使用的,
其他类型的函数(箭头函数、方法简写,generator
)都无法使用构造器,也就是说,不能用 new
操作符调用。
MDN: TypeError: “x” is not a constructor
是因为尝试将不是构造器的对象或者变量来作为构造器使用。
原文链接
阅读规范会发现 JavaScript 对象具有定义其特定行为的内部方法。
ECMAScript 引擎中的每个对象都与一组定义其运行时行为的内部方法相关联。
有“基本的内部方法”,范围从例如[[GetPrototypeOf]]
到[[OwnPropertyKeys]]
.
当我们处理函数时(记住这些也是对象),还可以有“附加的基本内部方法”,其中包括[[Call]]
和[[Construct]]
。[[Construct]]
是我们使用new
或super
创建新对象时使用的东西。
事实证明,并非每个函数都包含[[Construct]]
,这意味着并非每个函数都是构造函数。
未标识为构造函数的内置函数对象不实现 [[Construct]] 内部方法,除非在特定函数的描述中另有说明。
查看操作的定义,new
我们会看到它应该在TypeError
任何时候抛出一个isConstructor
错误。isContructor
查找[[Construct]]
内部方法。
那么,让我们看看下面的三行代码,看看当我们想要使用 函数 Fn
Arrow
Shorthand
作为构造函数时会发生什么:
const example = {
Fn: function() { console.log(this); },
Arrow: () => { console.log(this); },
Shorthand() { console.log(this); }
};
new example.Fn(); // Fn {}
new example.Arrow(); // Uncaught TypeError: example.Arrow is not a constructor
new example.Shorthand(); // Uncaught TypeError: example.Shorthand is not a constructor
每个函数创建的定义都归结为FunctionCreate
EcmaScript 规范中的定义。
规格FunctionCreate
非常明确:
FunctionCreate
FunctionCreate (kind, ParameterList, Body, Scope, Strict, prototype)
The abstract operation FunctionCreate requires the arguments: kind which is one of (Normal, Method, Arrow), a parameter list production specified by ParameterList, a body production specified by Body, a Lexical Environment specified by Scope, a Boolean flag Strict, and optionally, an object prototype. FunctionCreate performs the following steps:
- If the prototype argument was not passed, then
- Let prototype be the intrinsic object %FunctionPrototype%.
- If kind is not Normal, let allocKind be
"non-constructor"
.- Else let allocKind be
"normal"
.- Let F be FunctionAllocate(prototype, Strict, allocKind).
- Return FunctionInitialize(F, kind, ParameterList, Body, Scope).
所以事实证明,只有类型的函数Normal
才能构造和实现[[Construct]]
。进一步阅读规范,您会发现箭头函数使用 kindArrow
而方法简写定义使用 kind Method
。这导致它们成为“非构造函数”。