Getters and Setters in JavaScript

Mosh Hamedani

Follow

Dec 29, 2019 – 5 min read

.

Koncepcja getterów i setterów jest dość powszechna wśród popularnych języków używanych obecnie. Czy kiedykolwiek potrzebowałeś upewnić się, że dana akcja zostanie wykonana zawsze przed lub po przypisaniu jakiejś wartości do właściwości obiektu? Jest to możliwe dzięki setterom. Możesz również wykonać dowolne przetwarzanie podczas pobierania wartości właściwości za pomocą getterów (np. formatowanie). Jednym ze sposobów implementacji getterów i setterów jest użycie metod, tak jak to się robi w Javie. Jednak od czasu ES5, mamy znacznie bardziej elegancką i praktyczną alternatywę dostępną poprzez użycie składni get i set. Cóż, zaczynajmy!

W JavaScript obiekty są kolekcjami właściwości i prawdopodobnie używałeś ich już wcześniej do przechowywania danych. Właściwość to po prostu para klucz-wartość. Oto przykład:

const options = {
timeout: 5000,
retries: 3,
ip: '192.168.1.20',
port: 4001,
};

Właściwości w obiekcie mogą być łatwo ustawiane i odczytywane, tak jak to:

artist.name = 'Carice Anouk van Houten';console.log(artist.name); //=> "Carice Anouk van Houten"

Znowu, to na pewno nie jest nic nowego, jeśli masz już jakieś doświadczenie z JavaScript. Aby odróżnić te zwykłe właściwości od innych typów, które zobaczymy w tym artykule, możemy nazwać te pierwsze „właściwościami danych”.

Getters i setters: stary sposób

Przed ES5, jedynym sposobem, w jaki musieliśmy zaimplementować getters i setters było użycie zwykłych metod. Tak jak w poniższym przykładzie:

W powyższym przykładzie zachowałem słowo kluczowe function, aby było jasne, że nie ma tu żadnej magii. Tylko zwykłe metody. Mogliśmy osiągnąć ten sam efekt, używając składni definicji metod ES2015, która jest krótsza i nieco bardziej elegancka:

const config = {
_port: 4001,
setPort(port) {
// ...
},
getPort() {
// ...
},
};

Używanie tego rodzaju getterów i setterów jest dość proste:

config.setPort(8080);
console.log(config.getPort()); //=> 8080

Powiększanie wartości odbywałoby się w ten sposób:

item.setQuantity(item.getQuantity() + 1);

Co wygląda naprawdę czasochłonnie w porównaniu z bezpośrednim inkrementowaniem właściwości:

item.quantity += 1;
// Or even simpler...
item.quantity++;

Gettery i setery: dlaczego?

W językach OO, takich jak Java, C++ czy C#, możliwe jest ujawnienie członków klasy na różnych poziomach poprzez użycie modyfikatorów dostępu (takich jak public, protected i private). Służy to do implementacji ważnej koncepcji OOP zwanej ukrywaniem danych.

Bardzo częstym zastosowaniem getterów i setterów w tych językach jest eksponowanie członków klasy w bezpieczny sposób. Na przykład, można zaimplementować tylko getter, aby upewnić się, że prywatny członek nigdy nie zostanie zmieniony z zewnątrz klasy. Setter, z kolei, może być użyty do sprawdzania poprawności dostarczonych wartości i zachowania integralności instancji tej klasy.

A co z JavaScriptem?

W JavaScript, sprawy mają się nieco inaczej. W momencie pisania tego artykułu, nie ma żadnych modyfikatorów dostępu w JS. Obecnie najlepszą opcją, jaką mamy, jest użycie symboli, które dają nam pewien poziom prywatności, gdy są używane jako klucze. Niektórzy ludzie jednak ich nie lubią. Zwłaszcza dlatego, że łatwo jest złamać tę prywatność za pomocą refleksji.

Nie uważam tego za prawdziwy problem, ponieważ języki, które mają refleksję, zwykle pozwalają programistom złamać enkapsulację w jakiś sposób. Problem, który widzę w symbolach, polega na tym, że nie są one tak praktyczne w użyciu, jak prosty prywatny accessor byłby. Dobrą wiadomością jest to, że propozycja EcmaScript, która obejmuje prywatne pola, jest już w fazie 3. I będą one odporne na wszelkiego rodzaju refleksje.

W przykładzie z poprzedniej sekcji nie używaliśmy symboli ani żadnej innej sztuczki, aby symulować prywatnego członka. Właściwość _port nie ma nic specjalnego sama w sobie. Jest to po prostu zwykła właściwość danych i jako taka może być ustawiona lub odczytana bezpośrednio, całkowicie omijając getter i setter, które stworzyliśmy.

Ponieważ wyjaśnianie symboli i innych technik enkapsulacji nie jest celem tego artykułu, nie implementuję prywatnych właściwości w jego przykładach kodu. Należy tylko pamiętać, że gettery i settery są powszechnie (ale nie zawsze) używane do zapewnienia dostępu do enkapsulowanych członków. Na koniec, zwróć uwagę na podkreślenie poprzedzające nazwę właściwości _port. Jest to de facto konwencja wśród programistów JS, wskazująca, że dana właściwość jest prywatna i nie powinna być dostępna spoza klasy, w której jest zdefiniowana.

Właściwości getterów i setterów: nowa droga z właściwościami accessor

Właściwości accessor są nowoczesnym sposobem definiowania getterów i setterów. Jeśli chodzi o ich definicję, to nie różnią się one zbytnio od naszego poprzedniego przykładu, ale to ich użycie jest naprawdę inne. Po pierwsze, dostosujmy nasz kod do użycia właściwości accessor:

Jak widać, w tym przykładzie zmieniły się tylko dwie rzeczy:

  • Zamiast metod setPort i getPort. Używamy składni set i get wraz z pojedynczą nazwą dla właściwości („port„, w tym przykładzie)
  • Nie potrzebujemy tutaj słowa kluczowego function. W rzeczywistości, jeśli spróbujesz go użyć, otrzymasz SyntaxError.

Jak używać właściwości accessor?

Jeśli definicja właściwości accessor jest dość podobna do tego, jak tworzymy stare szkolne gettery i settery, ich użycie nie ma widocznej różnicy od tego, jak używamy zwykłych właściwości danych:

config.port = 8080;
console.log(config.port); //=> 8080

A oto jak wygląda wyrażenie inkrementacyjne:

timer.seconds += 1;

Tak. To takie proste. =)

Wnioski

  • Obiekty są kolekcjami właściwości
  • Zwykła właściwość jest po prostu parą klucz-wartość i może być nazywana „właściwością danych”
  • Możesz zaimplementować gettery i settery jako normalne metody. Jest to „staroszkolny” sposób robienia tego w JavaScript.
  • Gettery i setery są zwykle używane do zapewnienia dostępu do prywatnych członków klasy.
  • Własności następcze mogą zachowywać się dokładnie tak, jak stare gettery i setery oparte na normalnych metodach, ale ich użycie jest zaprojektowane tak, aby wyglądały jak właściwości danych.

Czy chcesz opanować JavaScript? Gorąco polecam kursy JavaScript Mosh’a.

I jeśli podobał Ci się ten artykuł, podziel się nim z innymi!

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.