wprowadzenie
JavaScript jest językiem opartym na prototypach, a każdy obiekt w JavaScript ma ukrytą wewnętrzną właściwość o nazwie]
, która może być używana do rozszerzania właściwości i metod obiektu. Więcej o prototypach przeczytasz w naszym samouczku Understanding prototypy and Inheritance in JavaScript.
do niedawna pracowici Programiści używali funkcji konstruktora do naśladowania obiektowego wzorca projektowego w JavaScript., Specyfikacja języka ECMAScript 2015, często określana jako ES6, wprowadziła klasy do języka JavaScript. Klasy w JavaScript w rzeczywistości nie oferują dodatkowej funkcjonalności i są często opisywane jako „cukier składniowy” nad prototypami i dziedziczeniem, ponieważ oferują czystszą i bardziej elegancką składnię. Ponieważ inne języki programowania używają klas, składnia klas w JavaScript ułatwia programistom poruszanie się między językami.
klasy są funkcjami
Klasa JavaScript jest typem funkcji., Klasy są deklarowane za pomocą słowa kluczowego class
. Będziemy używać składni wyrażenia funkcji do inicjalizacji funkcji i składni wyrażenia klasy do inicjalizacji klasy.
// Initializing a function with a function expressionconst x = function() {}
// Initializing a class with a class expressionconst y = class {}
możemy uzyskać dostęp do]
obiektu za pomocą metodyObject.getPrototypeOf()
. Użyjmy tego do przetestowania pustej funkcji, którą stworzyliśmy.
Object.getPrototypeOf(x);
Outputƒ () { }
możemy również użyć tej metody na klasie, którą właśnie stworzyliśmy.,
Object.getPrototypeOf(y);
Outputƒ () { }
kod zadeklarowany za pomocą function
I class
oba zwracają funkcję ]
. W przypadku prototypów każda funkcja może stać się instancją konstruktora, używając słowa kluczowego new
.
Outputx {}constructor: ƒ ()
dotyczy to również klas.
Outputy {}constructor: class
te przykłady konstruktorów prototypów są w przeciwnym razie puste, ale możemy zobaczyć, jak pod składnią obie metody osiągają ten sam efekt końcowy.,
Definiowanie klasy
w samouczku prototypów i dziedziczenia stworzyliśmy przykład oparty na tworzeniu postaci w tekstowej grze RPG. Kontynuujmy ten przykład tutaj, aby zaktualizować składnię z funkcji do klas.
funkcja konstruktora jest inicjalizowana szeregiem parametrów, które zostaną przypisane jako właściwościthis
, odnoszące się do samej funkcji. Pierwsza litera identyfikatora byłaby pisana wielką literą przez Konwencję.
// Initializing a constructor functionfunction Hero(name, level) { this.name = name; this.level = level;}
Kiedy przetłumaczymy to na składnię klasy, pokazaną poniżej, widzimy, że jest ona skonstruowana bardzo podobnie.
// Initializing a class definitionclass Hero { constructor(name, level) { this.name = name; this.level = level; }}
wiemy, że funkcja konstruktora ma być schematem obiektu przez kapitalizację pierwszej litery inicjalizatora (co jest opcjonalne) i przez znajomość składni. Słowo kluczoweclass
komunikuje w bardziej prosty sposób cel naszej funkcji.,
jedyną różnicą w składni inicjalizacji jest użycie słowa kluczowego class
zamiastfunction
I przypisanie właściwości wewnątrz metodyconstructor()
.
Definiowanie metod
powszechną praktyką w funkcjach konstruktora jest przypisywanie metod bezpośrednio do prototype
zamiast w inicjalizacji, jak widać w greet()
metoda poniżej.
z klasami składnia ta jest uproszczona, a metodę można dodać bezpośrednio do klasy., Używając skrótu definicji metody wprowadzonego w ES6, definiowanie metody jest jeszcze bardziej zwięzłym procesem.
przyjrzyjmy się tym właściwościom i metodom w działaniu. Utworzymy nową instancję Hero
używając słowa kluczowego new
I przypiszemy pewne wartości.
const hero1 = new Hero('Varg', 1);
Jeśli wydrukujemy więcej informacji o naszym nowym obiekcie za pomocąconsole.log(hero1)
, możemy zobaczyć więcej szczegółów o tym, co dzieje się z inicjalizacją klasy.,
OutputHero {name: "Varg", level: 1}__proto__: ▶ constructor: class Hero ▶ greet: ƒ greet()
możemy zobaczyć na wyjściu, żeconstructor()
Igreet()
funkcje zostały zastosowane do__proto__
lub]
zhero1
, a nie bezpośrednio jako metoda na obiekciehero1
. Chociaż jest to oczywiste podczas tworzenia funkcji konstruktora, nie jest to oczywiste podczas tworzenia klas. Klasy pozwalają na bardziej prostą i zwięzłą składnię, ale poświęcają pewną jasność w procesie.,
Rozszerzanie klasy
zaletą funkcji konstruktora i klas jest to, że mogą one być rozszerzane o nowe schematy obiektów oparte na rodzicu. Zapobiega to powtarzaniu kodu dla obiektów, które są podobne, ale wymagają dodatkowych lub bardziej szczegółowych funkcji.
nowe funkcje konstruktora mogą być tworzone z rodzica przy użyciu metodycall()
., W poniższym przykładzie utworzymy bardziej konkretną klasę znaków o nazwie Mage
I przypiszemy jej właściwości Hero
za pomocą call()
, a także dodamy dodatkową właściwość.
w tym momencie możemy utworzyć nową instancję Mage
używając tych samych właściwości co Hero
, jak również nową, którą dodaliśmy.,
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
wysyłająchero2
do konsoli, widzimy, że stworzyliśmy nowyMage
oparty na konstruktorze.
OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}__proto__: ▶ constructor: ƒ Mage(name, level, spell)
w klasach ES6, słowo kluczowesuper
jest używane zamiastcall
aby uzyskać dostęp do funkcji nadrzędnych. Użyjemy extends
, aby odwołać się do klasy nadrzędnej.
teraz możemy utworzyć nową instancjęMage
w ten sam sposób.,
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
wydrukujemyhero2
do konsoli i obejrzymy wyjście.
OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}__proto__: Hero ▶ constructor: class Mage
wyjście jest prawie dokładnie takie samo, z wyjątkiem tego, że w konstrukcji klasy]
jest powiązane z rodzicem, w tym przypadkuHero
.
Poniżej znajduje się porównanie obok siebie całego procesu inicjalizacji, dodawania metod i dziedziczenia funkcji konstruktora i klasy.
chociaż składnia jest zupełnie inna, wynik bazowy jest prawie taki sam między obiema metodami. Klasy dają nam bardziej zwięzły sposób tworzenia schematów obiektów, a funkcje konstruktora dokładniej opisują to, co dzieje się pod maską.
podsumowanie
w tym tutorialu dowiedzieliśmy się o podobieństwach i różnicach między funkcjami konstruktora JavaScript a klasami ES6. Zarówno klasy, jak i konstruktory imitują obiektowy model dziedziczenia do JavaScript, który jest językiem dziedziczenia opartym na prototypach.,
zrozumienie dziedziczenia prototypowego jest najważniejsze, aby być skutecznym programistą JavaScript. Znajomość klas jest niezwykle pomocna, ponieważ popularne biblioteki JavaScript, takie jak React, często korzystają ze składni class
.