Enkapsulacja danych w JavaScript: gettery i settery

Inkapsulacja danych w JavaScript: gettery i settery

Podczas budowania większych aplikacji JavaScript, szybko pojawia się potrzeba podzielenia ich na moduły połączone jasnymi kontraktami. Jeśli chodzi o długoterminowe utrzymanie, należy zapewnić sposób na zachowanie kompatybilności po zmianach interfejsu. Aby to zrobić, języki obiektowe polegają na enkapsulacji lub informacji ukrywającej szczegóły implementacji przed użytkownikami kawałka kodu, tak aby mógł się on zmienić bez wpływu na klientów.

W tym poście porozmawiamy o enkapsulacji danych w JavaScript. Dokładniej, porozmawiamy o enkapsulacji właściwości za getterami i setterami.

Pewne koncepcje

JavaScript został zaprojektowany mając zasadę kaczego typowania jako podstawę:

“Kiedy widzę ptaka, który chodzi jak kaczka, pływa jak kaczka i kwacze jak kaczka, nazywam tego ptaka kaczką.”

Innymi słowy, w swojej istocie, JavaScript jest językiem obiektowym, ale inaczej niż inne języki obiektowe takie jak C# i Java, w JavaScript klasy są obywatelami drugiej kategorii, a interfejsy nie istnieją. Obiekty nie mają typów, a zatem kod musi być napisany tak, aby interfejsował do obiektów, które mają określone właściwości i metody. Kontrakty między modułami są oparte na zestawie metod i właściwości, które zakłada się, że są obecne w wymienianych obiektach.

Enkapsulacja jest fundamentalna w programowaniu obiektowym. Oznacza to, że dany obiekt powinien być w stanie ukryć szczegóły swojego wewnętrznego działania, tak aby inne obiekty wchodzące z nim w interakcję nie zależały od szczegółów jego implementacji, ale od uzgodnionego na wysokim poziomie interfejsu. To czyni życie programistów prostszym, zarówno po stronie dostawcy, jak i po stronie użytkowników, ponieważ obaj wiedzą, że szczegóły implementacji mogą się zmieniać bez łamania obiektów klienta.

Dlaczego eksponowanie danych na interfejsie jest złym pomysłem

W JavaScript obiekt jest po prostu słownikiem nazw właściwości odwzorowanych na wartości, kiedy wartość właściwości jest funkcją, nazywamy ją metodą. Interfejs między metodami to zestaw właściwości, które kod klienta spodziewa się znaleźć na obiekcie.

Jeśli obiekt eksponuje tylko metody, łatwo jest sprawić, by interfejs ewoluował wraz z czasem. Metoda może sprawdzać swoje parametry i odpowiednio reagować. Możliwe jest również tworzenie nowych metod dostarczających nowych funkcji. I wspierać stare, które dostosowują stare zachowanie do nowego. Z właściwościami nie jest to możliwe.

W przypadku właściwości, utrzymanie stabilnego interfejsu nie jest łatwe. Domyślnie bowiem kod klienta może odwoływać się do nieistniejących właściwości obiektu. Pisanie do nieistniejącej właściwości spowoduje jej utworzenie. Odczytanie jej zwróci wartość undefined. Kod klienta nie będzie w stanie szybko wykryć, czy używa przestarzałych właściwości. Co gorsza, błąd może rozprzestrzeniać się na inne części kodu, utrudniając wykrycie problemu.

Standardowe API JavaScript posiada metody, które mogą być przydatne w unikaniu takich problemów: możliwe jest zamrożenie lub zapieczętowanie obiektu, aby nie można było używać nieobsługiwanych nazw właściwości.

Getter/Setters to save the day

Ukrywanie szczegółów implementacji metod jest łatwe.

Gettery/settery zostały oficjalnie wprowadzone do języka w ECMAScript 5.1 (ECMA-262). Są one obecnie obsługiwane we wszystkich głównych przeglądarkach desktopowych i mobilnych.

Podstawową ideą jest to, że dodaje składnię do definiowania właściwości accessora jako metody, zamiast prostych właściwości danych. Getter jest zdefiniowany przez słowo kluczowe get, po którym następuje funkcja nazwana po właściwości, nie przyjmująca żadnych argumentów i zwracająca wartość właściwości. Setter jest zdefiniowany przez słowo kluczowe set, po którym następuje funkcja nazwana po właściwości, przyjmująca jako parametr nową wartość właściwości.

Następujący przykład ilustruje getter i setter użyte do zdefiniowania właściwości accessor o nazwie prop:

var obj = { v: 0, get prop() { return this.v; }, set prop(newValue) { this.v = newValue; }};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);

Output:

042

Można również utworzyć właściwość tylko do odczytu, definiując getter bez settera:

var obj = { get prop() { return -1; },};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);

Output:

-1-1

Własność można wtedy zastąpić kilkoma metodami, które w przypadku zmiany implementacji klasy, mogą na nią zareagować i dostosować zachowanie klasy. W najgorszym przypadku, może podnieść wyjątek, aby poinformować użytkownika, że właściwość jest przestarzała i nie powinna być już używana.

Dalsza lektura

Mam nadzieję, że nauczyłeś się czegoś nowego o projektowaniu złożonych ewolucyjnych aplikacji w JavaScript w tym poście. W tej sekcji podam Ci kilka linków do odnośników zawierających więcej informacji.

Artykuły wprowadzające

Ta sekcja przynosi kilka krótkich artykułów prezentujących koncepcje i dających przegląd powiązanych API:

  1. Property getters and setters.
  2. JavaScript Getters and Setters

Więcej zaawansowanych artykułów

Te artykuły mówią o bardziej zaawansowanych powiązanych tematach, takich jak problemy powodowane przez gettery i setery, oraz jak je rozwiązać.

  1. Dlaczego getters/setters jest złym pomysłem w JavaScript
  2. Enkapsulacja danych w JavaScript

Dokumentacja źródłowa

Na koniec, aby naprawdę opanować temat, linki do dokumentacji mozilli powiązanych API:

  1. get i set pozwalają definiować getters i setters. Poza tym, co wyjaśniliśmy tutaj. Istnieją inne interesujące cechy, takie jak wsparcie dla dynamicznie generowanych nazw właściwości, oraz używanie getterów i setterów do symulowania ustawiania/pozyskiwania wartości w tablicy
  2. seal i freeze pozwalają kontrolować, które właściwości obiektu są modyfikowalne lub nie i jak. Może to być użyte do uniknięcia sytuacji, w której klienci używają przestarzałych części API obiektu.
  3. defineProperty pozwala na definiowanie getterów i setterów, a jednocześnie ma większą kontrolę nad tym, jak te właściwości są widziane przez klientów i jak bardzo są modyfikowalne.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.