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:
So IsConstructor is where we need to look next.
Both the summary and the steps describe this:
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:
That calls DefineMethod with just one argument, object. Let's look at DefineMethod - here's what we need:
Since functionPrototype was not passed as a parameter, the kind is
Method
. Let's look at what FunctionCreate does with that: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.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:
..but now you know how they aren't constructors, officially.