Stefan Judis Web Development

November 07, 2017 0 Comments

Stefan Judis Web Development



Šime Vidas recently tweeted about the object method shorthand definition. The tweet described that shorthand method defintions are not constructable and can not be used with the new keyword.

You can’t invoke an object method as a constructor if you’ve used the shorthand syntax.

I'm not using the new keyword very often these days but this fact surprised me. So I started digging the EcmaScript spec to figure out what differences arrow functions and the shorthand have in comparison to function property definitions.

There are three ways to define a method in an object and they're not only syntatically different but also behave differently.

The "constructable differences"

Reading the specification it turns out that JavaScript objects have internal methods that define their specific behavior.

Each object in an ECMAScript engine is associated with a set of internal methods that defines its runtime behaviour.

There are "essential internal methods" and these range from e.g. [[GetPrototypeOf]] to [[OwnPropertyKeys]].

When we're dealing with functions (and remember these are objects, too) there can be also "additional Essential Internal Methods" which include [[Call]] and [[Construct]]. [[Construct]] is what is used when we use new or super to create a new object.

It turns out though that not every function includes [[Construct]] which means that not every function is a constructor function.

Built-in function objects that are not identified as constructors do not implement the [[Construct]] internal method unless otherwise specified in the description of a particular function.

Looking at the definition of the new operations we'll see that it is supposed to throw a TypeError whenever isConstructor is false. isContructor looks up the [[Construct]] internal method.

If IsConstructor (constructor) is false, throw a TypeError exception.

So, let's look at the following three lines of code and see what happens when we want to use the functions Fn, Arrow and Shorthand as a constructor:

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

That's the surprising part of Šime's tweet.

The definition for every function creation goes down to FunctionCreate defined in the EcmaScript spec.

The spec for FunctionCreate is very clear:

FunctionCreate (kind, ParameterList, Body, Scope, Strict, prototype) 
[...] 1. If the prototype argument was not passed, then a. Let prototype be the intrinsic object %FunctionPrototype%. 2. If "kind" is not Normal, let allocKind be "non-constructor". [...]

So it turns out that only functions of type Normal will be constructable and will implement [[Construct]]. Reading the spec further you'll find that arrow functions use kind Arrow and method shorthand definitions use kind Method. This results in them being a "non-constructor".

That's it and this is where this behavior come from.

Tag cloud