JavaScript używa dziedziczenia prototypowego: każdy obiekt dziedziczy właściwości i metody ze swojego prototypowego obiektu.

tradycyjna Klasa jako schemat tworzenia obiektów, używana w językach takich jak Java czy Swift, nie istnieje w JavaScript. Dziedziczenie prototypowe dotyczy tylko obiektów.

dziedziczenie prototypowe może naśladować Klasyczne dziedziczenie klas. Aby przenieść tradycyjne klasy do JavaScript, standard ES2015 wprowadza składnięclass: cukier składniowy nad dziedziczeniem prototypowym.,

ten post zapoznaje cię z klasami JavaScript: jak zdefiniować klasę, zainicjalizować instancję, zdefiniować pola i metody, zrozumieć prywatne i publiczne pola, zrozumieć statyczne pola i metody.

1. Definicja: słowo kluczowe klasy

specjalne słowo kluczowe class definiuje klasę w JavaScript:

class User { // The body of class}

powyższy kod definiuje klasę User. Nawiasy klamrowe { } ograniczają ciało klasy. Zauważ, że składnia ta nosi nazwę class declaration.,

nie jesteś zobowiązany do podawania nazwy klasy. Używając wyrażenia klasy możesz przypisać klasę do zmiennej:

const UserClass = class { // The body of class};

możesz łatwo wyeksportować klasę jako część modułu ES2015. Oto składnia domyślnego eksportu:

export default class User { // The body of class}

i nazwanego eksportu:

export class User { // The body of class}

klasa staje się użyteczna podczas tworzenia instancji klasy. Instancja jest obiektem zawierającym dane i zachowanie opisane przez klasę.,

operatornew tworzy instancję klasy w JavaScript:instance = new Class().

na przykład możesz utworzyć instancję klasy User używając operatora new:

const myUser = new User();

new User() tworzy instancja klasy User.

2. Inicjalizacja: constructor()

constructor(param1, param2, ...) jest specjalną metodą w ciele klasy, która inicjalizuje instancję., Jest to miejsce, w którym ustawia się początkowe wartości pól lub wykonuje się dowolne konfiguracje obiektów.

w poniższym przykładzie konstruktor ustawia wartość początkową pola name:

class User { constructor(name) { this.name = name; }}

Userkonstruktor ma jeden parametr name, który służy do ustawienia wartości początkowej pola this.name.

wewnątrz konstruktora this wartość jest równa nowo utworzonej instancji.,

argumenty użyte do utworzenia instancji klasy stają się parametrami konstruktora:

class User { constructor(name) { name; // => 'Jon Snow' this.name = name; }}const user = new User('Jon Snow');

name parametr wewnątrz konstruktora ma wartość'Jon Snow'.

Jeśli nie zdefiniujesz konstruktora dla klasy, zostanie utworzony domyślny konstruktor. Konstruktor domyślny jest pustą funkcją, która nie modyfikuje instancji.

w tym samym czasie Klasa JavaScript może mieć do jednego konstruktora.

3. Pola

pola klasy są zmiennymi przechowującymi informacje., Pola mogą być dołączane do 2 encji:

  1. pola na instancji klasy
  2. pola na samej klasie (aka static)

pola mają również 2 poziomy dostępności:

  1. Public: pole jest dostępne w dowolnym miejscu
  2. Private: pole jest dostępne tylko w ciele Klasy

3.1 pola instancji publicznej

spójrzmy jeszcze raz w poprzednim fragmencie kodu:

class User { constructor(name) { this.name = name; }}

wyrażenie this.name = name tworzy pole wystąpienia name I przypisuje mu wartość początkową.,

później możesz uzyskać dostęp do polaname używając dostępu do właściwości:

const user = new User('Jon Snow');user.name; // => 'Jon Snow'

name jest polem publicznym, ponieważ możesz uzyskać do niego dostęp pozaUser class body.

gdy pola są tworzone pośrednio wewnątrz konstruktora, tak jak w poprzednim scenariuszu, może być trudno uchwycić listę pól. Musisz je odszyfrować z kodu konstruktora.

lepszym podejściem jest jawne deklarowanie pól klasy., Bez względu na to, co zrobi konstruktor, instancja zawsze ma ten sam zestaw pól.

propozycja pól klasy pozwala zdefiniować pola wewnątrz ciała klasy. Dodatkowo możesz podać wartość początkową od razu:

class SomeClass { field1; field2 = 'Initial value'; // ...}

zmodyfikuj klasę User i zadeklaruj publiczne pole name:

class User { name; constructor(name) { this.name = name; }}const user = new User('Jon Snow');user.name; // => 'Jon Snow'

name; wewnątrz ciała klasy deklaruje publiczne pole name.,

publiczne pola zadeklarowane w ten sposób są wyraziste: wystarczy rzucić okiem na deklaracje pól, aby zrozumieć strukturę danych klasy.

Co więcej, pole class można zainicjować od razu przy deklaracji.

class User { name = 'Unknown'; constructor() { // No initialization }}const user = new User();user.name; // => 'Unknown'

name = 'Unknown' wewnątrz ciała klasy deklaruje polename I inicjalizuje je wartością'Unknown'.

nie ma ograniczeń dostępu ani aktualizacji publicznych pól., Wartości można odczytywać i przypisywać do publicznych pól wewnątrz konstruktora, metod i poza klasą.

3.2 prywatne pola instancji

enkapsulacja jest ważną koncepcją, która pozwala ukryć wewnętrzne szczegóły klasy. Ktoś, kto używa zamkniętej klasy, zależy tylko od publicznego interfejsu, który zapewnia klasa i nie łączy się ze szczegółami implementacji klasy.

klasy zorganizowane z myślą o enkapsulacji są łatwiejsze do aktualizacji po zmianie szczegółów implementacji.,

dobrym sposobem na ukrycie wewnętrznych danych obiektu jest użycie pól prywatnych. Są to pola, które mogą być odczytywane i zmieniane tylko w obrębie klasy, do której należą. Świat zewnętrzny klasy nie może zmieniać pól prywatnych bezpośrednio.

prywatne pola są dostępne tylko w treści klasy.

przedrostek Nazwa pola ze specjalnym symbolem#aby uczynić go prywatnym, np.#myField., Prefiks # musi być przechowywany za każdym razem, gdy pracujesz z polem: declare it, read it, or modify it.

upewnijmy się, że pole #name może być ustawione raz przy inicjalizacji instancji:

#name jest polem prywatnym. Możesz uzyskać dostęp i modyfikować #namew treści User. Metoda getName() (więcej o metodach w następnej sekcji) może uzyskać dostęp do pola prywatnego #name.,

ale jeśli spróbujesz uzyskać dostęp do prywatnego pola #name pozaUser ciało klasy, zostanie wyświetlony błąd składni: SyntaxError: Private field '#name' must be declared in an enclosing class.

3.3 publiczne pola statyczne

Możesz również zdefiniować pola w samej klasie: pola statyczne. Są one pomocne do definiowania stałych klas lub przechowywania informacji specyficznych dla klasy.

aby utworzyć statyczne pola w klasie JavaScript, użyj specjalnego słowa kluczowego static, a następnie nazwy pola: static myStaticField.,

dodajmy nowe poletype, które wskazuje typ użytkownika: admin lub regular. Pola statyczne TYPE_ADMIN I TYPE_REGULAR są przydatnymi stałymi do rozróżniania typów użytkowników:

static TYPE_ADMIN I static TYPE_REGULAR definiują statyczne zmienne wewnątrz User class. Aby uzyskać dostęp do pól statycznych, musisz użyć klasy, po której następuje nazwa pola: User.TYPE_ADMIN I User.TYPE_REGULAR.

3.,4 prywatne pola statyczne

czasami nawet pola statyczne są szczegółami implementacji, które chcesz ukryć. W związku z tym można uczynić pola statyczne prywatnymi.

aby pole statyczne stało się prywatne, przedrostek nazwy pola oznaczający #symbol specjalny: static #myPrivateStaticField.

Załóżmy, że chcesz ograniczyć liczbę instancji klasyUser., Aby ukryć szczegóły dotyczące limitów instancji, możesz utworzyć prywatne pola statyczne:

pole statyczne User.#MAX_INSTANCESustawia maksymalną liczbę dozwolonych wystąpień, podczas gdy User.#instances pole statyczne zlicza rzeczywistą liczbę wystąpień.

te prywatne pola statyczne są dostępne tylko w klasieUser. Nic ze świata zewnętrznego nie może zakłócać mechanizmu ograniczeń: taka jest korzyść z enkapsulacji.

4. Metody

pola przechowują dane., Ale możliwość modyfikowania danych jest wykonywana przez specjalne funkcje, które są częścią klasy: metody.

klasy JavaScript obsługują zarówno metody instancyjne, jak i statyczne.

4.1 metody instancji

metody instancji mogą uzyskiwać dostęp i modyfikować dane instancji. Metody instancji mogą wywoływać inne metody instancji, jak również dowolne metody statyczne.,

na przykład zdefiniujmy metodę getName() która zwraca nazwę w User class:

w metodzie klasowej, a także w konstruktorze, this wartość jest równa instancji klasy. Użyj this, aby uzyskać dostęp do danych instancji: this.field, lub nawet wywołaj inne metody: this.method().,

dodajmy nową metodęnameContains(str) która ma jeden parametr i wywołuje inną metodę:

nameContains(str) { ... } jest metodąUser klasa, która akceptuje jeden parametr str. Co więcej, wykonuje inną metodę instancji this.getName(), aby uzyskać nazwę użytkownika.

metoda może być również prywatna. Aby uczynić metodę prywatną prefiksem jej nazwy z #.

zróbmygetName() metoda prywatna:

#getName() jest metodą prywatną., Wewnątrz metody nameContains(str) wywołujesz prywatną metodę w taki sposób: this.#getName().

będąc prywatną,#getName() nie może być wywołana pozaUser ciało klasy.

4.2 Gettery i settery

getter i setter naśladują zwykłe pole, ale mają większą kontrolę nad tym, jak jest dostępne i zmieniane pole.

getter jest wykonywany przy próbie uzyskania wartości pola, podczas gdy setter przy próbie ustawienia wartości.,

aby upewnić się, że name właściwość User nie może być pusta, zawińmy prywatne pole #nameValue w getterze i setterze:

get name() {...} Getter jest wykonywany po uzyskaniu dostępu do wartości pola: user.name.

4.3 metody statyczne

metody statyczne są funkcjami dołączonymi bezpośrednio do klasy. Trzymają logikę związaną z klasą, A nie z instancją klasy.,

aby utworzyć statyczną metodę, użyj specjalnego słowa kluczowego static, a następnie standardowej składni metody: static myStaticMethod() { ... }.

podczas pracy z metodami statycznymi należy pamiętać o dwóch prostych regułach:

  1. statyczna metoda może uzyskać dostęp do pól statycznych
  2. statyczna metoda nie może uzyskać dostępu do pól instancji.

na przykład, stwórzmy statyczną metodę, która wykrywa, czy użytkownik o określonej nazwie został już wzięty.,

isNameTaken() jest metodą statyczną, która używa statycznego pola prywatnegoUser.#takenNames do sprawdzania pobranych nazw.

5. Dziedziczenie: rozszerza

klasy w JavaScript obsługują pojedyncze dziedziczenie za pomocą słowa kluczowego extends.

w wyrażeniuclass Child extends Parent { }Child klasa dziedziczy zParent konstruktor, pola i metody.

na przykład utwórzmy nową klasę potomną ContentWriter, która rozszerza klasę nadrzędnąUser.,

ContentWriter dziedziczy zUser konstruktora, metodygetName() I polaname. Ponadto KlasaContentWriter deklaruje nowe poleposts.

zauważ, że prywatne Członkowie klasy rodzica nie są dziedziczone przez klasę potomną.

5.1 Konstruktor rodzica: super() w konstruktorze ()

Jeśli chcesz wywołać konstruktor rodzica w klasie potomnej, musisz użyć specjalnej funkcjisuper() dostępnej w konstruktorze potomnym.,

na przykład zróbmy ContentWriter konstruktor wywołujący konstruktor nadrzędny User, a także zainicjalizujmy pole postów:

super(name) wewnątrz klasy potomnej ContentWriter div>wykonuje konstruktor klasy nadrzędnej User.

zauważ, że wewnątrz konstruktora podrzędnego musisz wykonać super()przed użyciem słowa kluczowegothis. Wywołaniesuper() upewnia się, że konstruktor nadrzędny inicjalizuje instancję.,

class Child extends Parent { constructor(value1, value2) { // Does not work! this.prop2 = value2; super(value1); }}

5.2 instancja rodzica: super in methods

Jeśli chcesz uzyskać dostęp do metody rodzica wewnątrz metody potomnej, możesz użyć specjalnego skrótusuper.

getName() klasy potomnejContentWriter uzyskuje dostęp do metodysuper.getName() bezpośrednio z klasy nadrzędnejUser.

Ta funkcja jest nazywana nadpisywaniem metod.

zauważ, że możesz użyćsuper również ze statycznymi metodami, aby uzyskać dostęp do statycznych metod rodzica.

6., Object type checking: instanceof

object instanceof Class is the operator that determines if object is an instance of Class.

Let’s see instanceof operator in action:

user is an instance of User class, user instanceof User evaluates to true.

The empty object {} is not an instance of User, correspondingly obj instanceof User is false.,

instanceof jest polimorficzny: operator wykrywa dziecko jako instancję klasy nadrzędnej.

writer jest instancją klasy potomnejContentWriter. Operator writer instanceof ContentWriter ocenia na true.

jednocześnieContentWriter jest klasą potomnąUser. Tak więc writer instanceof Userocenia do true.

Co zrobić, jeśli chcesz określić dokładną klasę instancji?, Możesz użyć właściwości constructor I porównać bezpośrednio z klasą:

writer.constructor === ContentWriter; // => truewriter.constructor === User; // => false

7. Klasy i prototypy

muszę powiedzieć, że składnia klasy w JavaScript robi świetną robotę, aby oderwać się od dziedziczenia prototypów. Aby opisać składnię class nie użyłem nawet terminu prototype.

ale klasy są zbudowane na dziedziczeniu prototypowym. Każda klasa jest funkcją i tworzy instancję, gdy jest wywoływana jako konstruktor.

poniższe dwa fragmenty kodu są równoważne.,

wersja klasy:

Wersja używająca prototype:

składnia klasy jest o wiele łatwiejsza w obsłudze, jeśli znasz klasyczny mechanizm dziedziczenia języków Java lub Swift.

tak czy inaczej, nawet jeśli używasz składni klas w JavaScript, polecam Ci dobrą znajomość dziedziczenia prototypowego.

8. Dostępność funkcji klasowych

funkcje klasowe przedstawione w tym poście są rozłożone na ES2015 i propozycje na etapie 3.,

pod koniec 2019 r.funkcje klas są podzielone między:

  • pola instancji publicznych i prywatnych są częścią propozycji pól klasowych
  • metody instancji prywatnych i Accesory są częścią propozycji metod prywatnych Klasy
  • publiczne i prywatne pola statyczne i prywatne metody statyczne są częścią propozycji właściwości statycznych Klasy
  • reszta jest częścią standardu ES2015.

9. Wnioski

klasy JavaScript inicjują instancje za pomocą konstruktorów, definiują pola i metody., Możesz dołączać pola i metody nawet na samej klasie, używając słowa kluczowego static.

dziedziczenie odbywa się za pomocą słowa kluczowegoextends: możesz łatwo utworzyć klasę potomną z rodzica. super słowo kluczowe jest używane do uzyskania dostępu do klasy rodzica z klasy potomnej.

aby skorzystać z enkapsulacji, Ustaw pola i metody jako prywatne, aby ukryć wewnętrzne szczegóły swoich klas. Nazwy prywatnych pól i metod muszą zaczynać się od #.,

klasy w JavaScript stają się coraz wygodniejsze w użyciu.

Co sądzisz o używaniu# do prefiksu własności prywatnych?