Dodatkowe funkcje klas w JavaScript
W tym artykule wyjaśnimy dodatkowe funkcje klas w JavaScript.
YouTube Video
Dodatkowe funkcje klas w JavaScript
Prywatne właściwości w JavaScript
W JavaScript prywatne właściwości to właściwości, które są dostępne tylko wewnątrz obiektu lub klasy. Umożliwia to bardziej bezpieczny i solidny projekt kodu dzięki zapewnieniu enkapsulacji, co uniemożliwia bezpośrednią modyfikację lub odwołanie z kodu zewnętrznego.
Wprowadzone w ECMAScript 2020 (ES11) w 2020 roku, użycie #
(hasha) do definiowania prywatnych pól wewnątrz klasy zostało zaprezentowane. Zapewnia to bardziej przejrzysty sposób, zastępując tradycyjne konwencje prywatne w JavaScript (takie jak nazwy zmiennych zaczynające się od podkreślenia).
Zalety prywatnych właściwości
Oto zalety prywatnych właściwości.
- Hermetyzacja: Ukrywa wewnętrzny stan przed otoczeniem i zapewnia spójność danych.
- Bezpieczeństwo: Zapobiega przypadkowym modyfikacjom właściwości przez kod zewnętrzny.
- Zwiększona łatwość utrzymania: Ukrywa implementację obiektów lub klas i wyjaśnia interfejs udostępniany na zewnątrz.
Jak używać prywatnych właściwości
Definiowanie prywatnych właściwości w klasach
Prywatne pola są definiowane za pomocą nazwy zaczynającej się od #
. To pole nie może być bezpośrednio dostępne z instancji klasy lub jej podklas.
1class Person {
2 // Define private property
3 #name;
4
5 constructor(name) {
6 this.#name = name;
7 }
8
9 // Method to access the private property
10 getName() {
11 return this.#name;
12 }
13
14 // Method to change the private property
15 setName(newName) {
16 this.#name = newName;
17 }
18}
19
20const john = new Person("John");
21console.log(john.getName()); // John
22
23// Cannot access private property directly
24console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class
W powyższym kodzie #name
jest prywatną właściwością, która nie może być bezpośrednio dostępna z zewnątrz klasy Person
. Możesz uzyskać dostęp do nazwy lub ją zmienić wyłącznie za pomocą metod getName
i setName
.
Definiowanie prywatnych metod
Podobnie jak prywatne właściwości, prywatne metody są również definiowane za pomocą nazwy zaczynającej się od #
. Prywatne metody mogą być wywoływane wyłącznie wewnątrz klasy.
1class Counter {
2 #count = 0;
3
4 increment() {
5 this.#count++;
6 this.#logCount(); // Calling private method
7 }
8
9 // Private method
10 #logCount() {
11 console.log(`Current count: ${this.#count}`);
12 }
13}
14
15const counter = new Counter();
16counter.increment(); // Current count: 1
17
18// Cannot access private method directly
19counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class
Tutaj #logCount
jest zdefiniowane jako prywatna metoda i nie można do niej uzyskać dostępu z zewnątrz klasy. Ta metoda jest używana wyłącznie wewnątrz klasy.
Zalety i uwagi dotyczące prywatnych właściwości
Zaleta
- Ponieważ nie można uzyskać do niego dostępu bezpośrednio z zewnątrz klasy, zapobiega się niezamierzonym zmianom lub operacjom.
- Ponieważ części niewidoczne z zewnątrz mogą być dobrze ukryte, można jasno zarządzać częściami ujawnianymi jako API.
Notatki
- Ponieważ prywatne pola są całkowicie ukryte przed dostępem z zewnątrz klasy, testowanie i debugowanie może być utrudnione. Dlatego ważne jest, aby dostarczyć API, które można dokładnie przetestować na etapie projektowania.
- Pola prywatne zachowują się inaczej niż inne części JavaScript oparte na cechach prototypowych, ponieważ są unikalne dla każdej instancji.
Tradycyjna pseudonimowa implementacja właściwości prywatnych
Przed wprowadzeniem prywatnych pól za pomocą #
, JavaScript nie posiadał oficjalnej składni dla właściwości prywatnych. Dlatego w przeszłości pseudo-prywatne właściwości były implementowane w następujący sposób.
Umowny sposób użycia podkreślenia
Programiści konwencjonalnie wskazywali 'prywatność', poprzedzając nazwy zmiennych podkreśleniem.
1class Car {
2 constructor(brand) {
3 this._brand = brand; // Using an underscore to indicate private
4 }
5
6 getBrand() {
7 return this._brand;
8 }
9}
10
11const car = new Car("Toyota");
12console.log(car.getBrand()); // Toyota
13console.log(car._brand); // Toyota (Accessible from outside)
Ta metoda jest jedynie 'konwencją', a w praktyce właściwości nadal mogą być dostępne z zewnątrz.
Implementacja właściwości prywatnych za pomocą domknięć
Możliwe jest również uzyskanie właściwości prywatnych za pomocą domknięć w zakresie funkcji.
1function createPerson(name) {
2 let _name = name; // Private variable within function scope
3
4 return {
5 getName: function() {
6 return _name;
7 },
8 setName: function(newName) {
9 _name = newName;
10 }
11 };
12}
13
14const person = createPerson("Alice");
15console.log(person.getName()); // Alice
16person.setName("Bob");
17console.log(person.getName()); // Bob
18
19// Cannot access directly from outside
20console.log(person._name); // undefined
Za pomocą tej metody zmienna _name
jest zamknięta w zakresie funkcji i nie można uzyskać do niej bezpośredniego dostępu z zewnątrz.
Podsumowanie
Właściwości prywatne w JavaScript są bardzo skuteczne w zapewnianiu enkapsulacji w projektowaniu klas i obiektów, pomagając bezpiecznie chronić dane. Notacja #
dla pól prywatnych wprowadzona w ES2020 zapewnia jaśniejszą i bezpieczniejszą metodę zarządzania prywatnością w porównaniu do tradycyjnych konwencji i domknięć.
Opcjonalne łańcuchowanie w JavaScript
Opcjonalne łańcuchowanie to bardzo przydatna składnia w JavaScript do uzyskiwania dostępu do właściwości głęboko zagnieżdżonych obiektów. Poprawia czytelność i łatwość utrzymania kodu, umożliwiając bezpieczny dostęp bez konieczności indywidualnego sprawdzania istnienia konkretnych właściwości.
Podstawowa składnia opcjonalnego łańcuchowania
Opcjonalne łańcuchowanie można zastosować, umieszczając ?
przed kropką (.
) lub notacją nawiasową używaną do uzyskania dostępu do właściwości. Ta notacja zwraca undefined
, gdy przetwarzana właściwość jest null
lub undefined
, pozwalając programowi na bezpieczne kontynuowanie przetwarzania bez generowania błędu.
Przykład:
1const user = {
2 name: 'John',
3 address: {
4 street: '123 Main St',
5 city: 'New York'
6 }
7};
8
9// Without using optional chaining
10const city = user && user.address && user.address.city;
11console.log(city); // New York
12
13// Using optional chaining
14const cityWithOptionalChaining = user?.address?.city;
15console.log(cityWithOptionalChaining); // New York
W tym przykładzie uzyskujemy dostęp do address
i jego właściwości city
obiektu user
. Bez użycia opcjonalnego łańcuchowania, konieczne byłoby wykonanie wielu kontroli istnienia, ale dzięki opcjonalnemu łańcuchowaniu można bezpiecznie uzyskać dostęp do właściwości za pomocą jednego wyrażenia.
Używanie opcjonalnego łańcuchowania z tablicami i funkcjami
Opcjonalne łańcuchowanie można stosować nie tylko do właściwości obiektów, ale także do elementów tablic oraz wywołań funkcji.
Przykład z tablicami:
1const users = [{ name: 'Alice' }, { name: 'Bob' }];
2
3// Accessing the non-existent third element
4const thirdUser = users[2]?.name;
5console.log(thirdUser); // undefined
Przykład z funkcjami:
1const user = {
2 greet: function() {
3 return 'Hello!';
4 }
5};
6
7// Call the function only if greet exists
8const greeting = user.greet?.();
9console.log(greeting); // Hello!
10
11// Return undefined if greet does not exist
12const nonExistentGreeting = user.nonExistentMethod?.();
13console.log(nonExistentGreeting); // undefined
Łączenie opcjonalnego łańcuchowania z wartościami domyślnymi
Podczas korzystania z opcjonalnego łańcuchowania często stosuje się logiczny operator LUB (||
) lub operator scalania domyślnego (??
) w celu określenia wartości domyślnych, jeśli właściwość nie istnieje.
Przykład:
1const user = {
2 name: 'John',
3 address: {
4 city: 'New York'
5 }
6};
7
8// Set a default value for a non-existent property
9const state = user?.address?.state || 'Unknown';
10console.log(state); // Unknown
11
12// Example using the nullish coalescing operator
13const zipCode = user?.address?.zipCode ?? '00000';
14console.log(zipCode); // 00000
Operator ||
traktuje false
, 0
, ''
itd., jako wartości fałszywe, natomiast operator ??
stosuje wartość domyślną tylko wtedy, gdy operand jest null
lub undefined
.
Korzyści z opcjonalnego łańcuchowania
- Bezpieczny dostęp do zagnieżdżonych obiektów: Dzięki opcjonalnemu łańcuchowaniu nie musisz już wykonywać jawnych kontroli istnienia, co sprawia, że kod jest bardziej zwięzły.
- Unikanie błędów: Opcjonalne łańcuchowanie może zapobiegać błędom w czasie wykonywania, nawet jeśli właściwość jest
null
lubundefined
. - Zwiększona czytelność i utrzymanie kodu: Zwłaszcza podczas pracy z wieloma zagnieżdżonymi obiektami, czytelność kodu jest znacznie poprawiona.
Ostrożności przy opcjonalnym łańcuchowaniu
- Częste używanie opcjonalnego łańcuchowania może być oznaką, że projekt struktury danych jest zbyt skomplikowany. Należy dążyć do prostego modelu danych.
- Ponieważ niektóre starsze przeglądarki i silniki JavaScript nie obsługują tej funkcji, konieczne może być użycie polyfilli lub transpilerów.
Wnioski
Opcjonalne łańcuchowanie to potężna funkcja, która upraszcza bezpieczny dostęp do właściwości i funkcji zagnieżdżonych obiektów w JavaScript. Jest szczególnie skuteczne podczas uzyskiwania dostępu do głęboko zagnieżdżonych struktur danych, przyczyniając się do zapobiegania błędom i poprawy czytelności kodu.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.