Jack Franklin

23 grudnia 2013

Po większej części, w JavaScript, to co widzisz jest tym, co dostajesz. Wartość jest wartością; nie ma żadnych sztuczek. Czasami jednak chcesz wartość, która jest oparta na innych wartościach: na przykład czyjeś pełne imię i nazwisko jest konkatenacją imienia i nazwiska. Jeśli masz obiekt person i chcesz, aby użytkownicy tego obiektu mogli ustawić pełne, pierwsze lub ostatnie imię i zobaczyć, że zmiana ta jest natychmiast odzwierciedlona w innych wartościach, konwencjonalnie zbudowałbyś go za pomocą funkcji:

person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith

Ale jest to brzydkie i wymaga od użytkowników twojego obiektu dbania o to, aby właściwości były powiązane; w bardziej złożonym przykładzie, może to nie być tak oczywiste, jak w przypadku nazw. Na szczęście istnieje lepszy sposób, dodany w ECMAScript 5.

Meet getters and setters.

How

Zróbmy obiekt osoby. Chcemy mieć możliwość ustawienia imienia, nazwiska lub pełnej nazwy i automatycznej aktualizacji dwóch pozostałych.

var person = { firstName: 'Jimmy', lastName: 'Smith', get fullName() { return this.firstName + ' ' + this.lastName; }, set fullName (name) { var words = name.toString().split(' '); this.firstName = words || ''; this.lastName = words || ''; }}

person.fullName = 'Jack Franklin';console.log(person.firstName); // Jackconsole.log(person.lastName) // Franklin

Więc co się tutaj dzieje?

Słowa kluczowe get i set są ważne. Następuje po nich właściwość, do której się odnoszą (fullName), oraz ciało funkcji, które określa zachowanie, gdy właściwość jest dostępna (name = person.fullName) lub modyfikowana (person.fullName = 'Some Name').

Te dwa słowa kluczowe definiują funkcje dostępowe: getter i setter dla właściwości fullName. Gdy właściwość jest dostępna, używana jest wartość zwracana przez getter. Kiedy wartość jest ustawiana, wywoływany jest setter i przekazywana jest wartość, która została ustawiona. Od ciebie zależy, co zrobisz z tą wartością, ale to, co jest zwracane z settera, to wartość, która została przekazana – więc nie musisz niczego zwracać.

Oficjalny sposób: Object.defineProperty

Wraz z metodą inline deklarowania getterów i setterów, można to również zrobić bardziej jawnie poprzez Object.defineProperty (MDN Documentation). Metoda ta przyjmuje trzy argumenty. Pierwszym z nich jest obiekt, do którego ma zostać dodana właściwość, drugim jest nazwa właściwości, a trzecim obiekt opisujący właściwość (znany jako deskryptor właściwości). Oto przykład, który replikuje powyższy przykład:

var person = { firstName: 'Jimmy', lastName: 'Smith'};

Object.defineProperty(person, 'fullName', {get: function() {return firstName + ' ' + lastName;},set: function(name) {var words = name.split(' ');this.firstName = words || '';this.lastName = words || '';}});

Zaleta nie jest tu od razu widoczna. Poza możliwością dodawania właściwości po utworzeniu obiektu początkowego, czy jest jakaś realna korzyść?

Gdy zdefiniujesz właściwość w ten sposób, możesz zrobić znacznie więcej niż tylko zdefiniować setter lub getter. Możesz również przekazać następujące klucze:

  • configurable (false domyślnie): jeśli jest to prawda, konfiguracja właściwości będzie modyfikowalna w przyszłości.
  • enumerable (false domyślnie): jeśli prawda, właściwość pojawi się podczas pętli nad obiektem (for (var key in obj)).

Możemy również zdefiniować właściwości, które nie mają jawnych getterów i setterów:

Object.defineProperty(person, 'age', { value: 42});

To utworzy person.age i ustawi ją na wartość 42. Ważne jest, aby zauważyć, że ta właściwość nie jest zapisywalna. Wywołanie person.age = 99 nie będzie miało żadnego efektu. W ten sposób możesz tworzyć właściwości tylko do odczytu. Jeśli właściwość ma ustawiony klucz value, to nie może mieć gettera ani settera. Właściwości mogą mieć wartości lub accessory, ale nie oba.

Nie tylko to, ale ponieważ właściwość enumerable jest domyślnie ustawiona na false, ta właściwość nie pojawi się, gdy wykonamy pętlę nad kluczami obiektu.

Jeżeli chcielibyśmy uczynić właściwość zapisywalną, musielibyśmy ustawić właściwość writable:

Object.defineProperty(person, 'age', { value: 42, writable: true});

Teraz, person.age = 99; przyniesie pożądany efekt.

Nadużywanie

Pamiętaj: tylko dlatego, że dana funkcja istnieje, nie musi być używana cały czas. Gettery i Settery mają swoje przypadki użycia, ale nie przesadzaj, bo najprawdopodobniej skończysz z projektem, który jest mylący dla tych, którzy wchodzą w interakcję z twoimi obiektami. Używane ostrożnie, są bardzo potężne. Ale z wielką mocą przychodzi wielka odpowiedzialność.

Pomoc dla przeglądarek?

IE9 i wyższe mają pełną obsługę Object.defineProperty, wraz z Safari 5+, Firefox 4+, Chrome 5+ i Opera 12+. Jeśli pracujesz z Node.js, masz pełne wsparcie. Czyż nie kochasz Node’a?!

Ten artykuł został napisany wspólnie z Tomem Ashworthem. Podziękowania dla Toma za pomoc w złożeniu tego razem.

Jeśli podobał Ci się ten post, dołącz do newslettera, aby otrzymywać aktualizacje o nowej zawartości 😎.

Wszystkie wpisy na blogu

Jeśli podobał Ci się ten post, koniecznie śledź mnie na Twitterze.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.