Běžné {...}
syntaxe nám umožňuje vytvořit jeden objekt. Často však potřebujeme vytvořit mnoho podobných objektů, například více uživatelů nebo položek nabídky a tak dále.
To lze provést pomocí funkcí konstruktoru a "new"
operátor.
Funkce konstruktoru
Funkce konstruktoru jsou technicky běžné funkce. Existují však dvě konvence:
- Jsou pojmenovány s velkým počátečním písmenem.
- Měly by být spouštěny pouze s
"new"
operátor.
Například:
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
Když je funkce spuštěna s new
, provede následující kroky:
- Je vytvořen nový prázdný objekt a přiřazen k
this
. - Tělo funkce se provede. Obvykle upravuje
this
, přidá do něj nové vlastnosti. - Hodnota
this
je vráceno.
Jinými slovy new User(...)
dělá něco jako:
function User(name) {
// this = {}; (implicitly)
// add properties to this
this.name = name;
this.isAdmin = false;
// return this; (implicitly)
}
Takže let user = new User("Jack")
dává stejný výsledek jako:
let user = {
name: "Jack",
isAdmin: false
};
Nyní, pokud chceme vytvořit další uživatele, můžeme zavolat new User("Ann")
, new User("Alice")
a tak dále. Mnohem kratší než pokaždé používat literály a také snadno čitelné.
To je hlavní účel konstruktorů – implementovat opakovaně použitelný kód pro vytváření objektů.
Poznamenejme ještě jednou – technicky jde o jakoukoli funkci (kromě funkcí šipek, protože nemají this
) lze použít jako konstruktor. Může být spuštěn s new
a provede výše uvedený algoritmus. „Velké písmeno napřed“ je běžná dohoda, aby bylo jasné, že funkce má být spuštěna s new
.
Pokud máme mnoho řádků kódu o vytvoření jediného komplexního objektu, můžeme je zabalit do okamžitě volané funkce konstruktoru, jako je tato:
// create a function and immediately call it with new
let user = new function() {
this.name = "John";
this.isAdmin = false;
// ...other code for user creation
// maybe complex logic and statements
// local variables etc
};
Tento konstruktor nelze znovu volat, protože není nikde uložen, pouze vytvořen a volán. Cílem tohoto triku je tedy zapouzdřit kód, který vytváří jediný objekt, bez budoucího opětovného použití.
Test režimu konstruktoru:new.target
Pokročilé věciSyntaxe z této sekce se používá zřídka, přeskočte ji, pokud nechcete vědět všechno.
Uvnitř funkce můžeme zkontrolovat, zda byla volána pomocí new
nebo bez něj, pomocí speciálního new.target
vlastnost.
Pro běžná volání není definována a rovná se funkci, je-li volána s new
:
function User() {
alert(new.target);
}
// without "new":
User(); // undefined
// with "new":
new User(); // function User { ... }
To lze použít uvnitř funkce, abyste zjistili, zda byla volána s new
, „v režimu konstruktoru“, nebo bez něj, „v běžném režimu“.
Můžeme také udělat oba new
a běžná volání, aby udělali totéž, jako je toto:
function User(name) {
if (!new.target) { // if you run me without new
return new User(name); // ...I will add new for you
}
this.name = name;
}
let john = User("John"); // redirects call to new User
alert(john.name); // John
Tento přístup se někdy používá v knihovnách, aby byla syntaxe flexibilnější. Aby lidé mohli volat funkci s nebo bez new
a stále to funguje.
Pravděpodobně není dobré používat všude, protože vynechání new
je trochu méně zřejmé, co se děje. S new
všichni víme, že se vytváří nový objekt.
Návrat od konstruktorů
Konstruktory obvykle nemají return
tvrzení. Jejich úkolem je zapsat všechny potřebné věci do this
a automaticky se stane výsledkem.
Ale pokud existuje return
pak je pravidlo jednoduché:
- Pokud
return
je volána s objektem, pak je vrácen objekt namístothis
. - Pokud
return
je voláno s primitivem, je ignorováno.
Jinými slovy return
s objektem vrátí tento objekt, ve všech ostatních případech this
je vráceno.
Například zde return
přepíše this
vrácením objektu:
function BigUser() {
this.name = "John";
return { name: "Godzilla" }; // <-- returns this object
}
alert( new BigUser().name ); // Godzilla, got that object
A zde je příklad s prázdným return
(nebo bychom za něj mohli umístit primitiv, na tom nezáleží):
function SmallUser() {
this.name = "John";
return; // <-- returns this
}
alert( new SmallUser().name ); // John
Konstruktéři obvykle nemají return
tvrzení. Zde zmiňujeme speciální chování s vracejícími se objekty především pro úplnost.
Mimochodem, za new
můžeme vynechat závorky , pokud nemá žádné argumenty:
let user = new User; // <-- no parentheses
// same as
let user = new User();
Vynechání závorek zde není považováno za „dobrý styl“, ale syntaxe je povolena specifikací.
Metody v konstruktoru
Použití funkcí konstruktoru k vytváření objektů poskytuje velkou flexibilitu. Funkce konstruktoru může mít parametry, které definují, jak vytvořit objekt a co do něj vložit.
Samozřejmě můžeme přidat do this
nejen vlastnosti, ale také metody.
Například new User(name)
níže vytvoří objekt s daným name
a metodu sayHi
:
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "My name is: " + this.name );
};
}
let john = new User("John");
john.sayHi(); // My name is: John
/*
john = {
name: "John",
sayHi: function() { ... }
}
*/
Chcete-li vytvářet složité objekty, existuje pokročilejší syntaxe, třídy, kterým se budeme věnovat později.
Shrnutí
- Funkce konstruktoru nebo stručně konstruktory jsou běžné funkce, ale existuje společná shoda na jejich pojmenování s velkým počátečním písmenem.
- Funkce konstruktoru by měly být volány pouze pomocí
new
. Takové volání znamená vytvoření prázdnéhothis
na začátku a vrácení obsazeného na konci.
Můžeme použít funkce konstruktoru k vytvoření více podobných objektů.
JavaScript poskytuje funkce konstruktoru pro mnoho vestavěných jazykových objektů:například Date
pro data Set
pro sady a další, které plánujeme studovat.
V této kapitole pokryjeme pouze základy o objektech a konstruktorech. Jsou nezbytné, abyste se v dalších kapitolách dozvěděli více o datových typech a funkcích.
Poté, co se to naučíme, vrátíme se k objektům a podrobně se jim budeme věnovat v kapitolách Prototypy, dědičnost a Třídy.