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.

W ECMAScript 2020 (ES11), wprowadzonym w 2020 roku, wprowadzono użycie znaku # do definiowania prywatnych pól w klasach. Zapewnia to bardziej przejrzystą metodę niż tradycyjna konwencja prywatna w JavaScript (np. nazwy zmiennych rozpoczynające się od podkreślenia). Zapewnia to bardziej przejrzysty sposób, zastępując tradycyjne konwencje prywatne w JavaScript (takie jak nazwy zmiennych zaczynające się od podkreślenia).

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

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.

1// Cannot access private property directly
2console.log(john.#name); // SyntaxError: Private field '#name' must be declared in an enclosing class

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

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.

1// Cannot access private method directly
2counter.#logCount(); // SyntaxError: Private field '#logCount' must be declared in an enclosing class

Zalety i uwagi dotyczące prywatnych właściwości

Zaleta

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

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 (optional chaining) to bardzo przydatna składnia w JavaScript do uzyskiwania dostępu do głęboko zagnieżdżonych właściwości 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

Opcjonalnego łańcuchowania można używać, umieszczając znak ? przed kropką lub notacją nawiasową używaną do uzyskiwania 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
  • W ten sposób możesz również uzyskiwać dostęp do elementów tablicy za pomocą opcjonalnego łańcuchowania.

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
  • Jak pokazano w tym przykładzie, można to również zastosować do wywołań funkcji.

Łą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 logicznego LUB traktuje wartości takie jak false, 0 oraz '' jako fałszywe, podczas gdy operator łączenia z wartością null używa wartości domyślnej tylko wtedy, gdy wartość wynosi 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