Šime Vidas nedávno tweetoval o zkrácené definici objektové metody. Tweet popsal, že zkrácené definice metody nejsou konstruovatelné a nelze je použít s new
klíčové slovo.
Nepoužívám new
klíčové slovo v dnešní době velmi často, ale tato skutečnost mě překvapila. Začal jsem tedy zkoumat specifikaci EcmaScript, abych zjistil, jaké rozdíly mají funkce šipek a zkratka ve srovnání s definicemi vlastností funkcí.
Existují tři způsoby, jak definovat metodu v objektu, a jsou nejen syntaticky odlišné, ale také se odlišně chovají.
"konstruovatelné rozdíly"
Při čtení specifikace se ukazuje, že objekty JavaScriptu mají interní metody, které definují jejich specifické chování.
Existují "základní interní metody" a ty se pohybují např. [[GetPrototypeOf]]
až [[OwnPropertyKeys]]
.
Když se zabýváme funkcemi (a pamatujte si, že se jedná také o objekty), mohou existovat také "další základní interní metody", které zahrnují [[Call]]
a [[Construct]]
. [[Construct]]
je to, co se používá, když používáme new
nebo super
vytvořit nový objekt.
Ukazuje se však, že ne každá funkce obsahuje [[Construct]]
což znamená, že ne každá funkce je funkcí konstruktoru.
Při pohledu na definici new
operací uvidíme, že má házet TypeError
kdykoli isConstructor
je nepravdivé. isContructor
vyhledá [[Construct]]
interní metoda.
Podívejme se tedy na následující tři řádky kódu a uvidíme, co se stane, když chceme použít funkce Fn
, Arrow
a Shorthand
jako konstruktor:
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
To je ta překvapivá část Šimeho tweetu.
Definice pro každé vytvoření funkce klesá na FunctionCreate
definované ve specifikaci EcmaScript.
Specifikace pro FunctionCreate
je velmi jasné:
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".
[...]
Ukazuje se tedy, že pouze funkce typu Normal
bude konstruovatelný a bude implementovat [[Construct]]
. Při dalším čtení specifikace zjistíte, že funkce šipek používají typ Arrow
a zkrácené definice metod používají druh Method
. To má za následek, že jsou "nekonstruktoři".
To je ono a odtud toto chování pochází.