Dodatkowe funkcje klas w JavaScript

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 lub undefined.
  • 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.

YouTube Video