Jack Franklin

December 23, 2013

V JavaScriptu většinou platí, že co vidíte, to dostanete. Hodnota je hodnota, neexistují žádné triky. Někdy však chcete hodnotu, která je založena na nějakých jiných hodnotách: například něčí celé jméno je zřetězením jeho jména a příjmení. Pokud máte objekt person a chcete, aby uživatelé tohoto objektu mohli nastavit celé, křestní nebo příjmení a aby se tato změna okamžitě projevila v ostatních hodnotách, konvenčně byste to sestavili pomocí funkcí:

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

To je ale ošklivé a vyžaduje to, aby se uživatelé vašeho objektu starali o to, že vlastnosti spolu souvisejí; ve složitějším příkladu to nemusí být tak zřejmé jako u jmen. Naštěstí existuje lepší způsob, přidaný v ECMAScriptu 5.

Seznamte se s gettery a settery.

Jak

Vytvořme tento objekt osoby. Chceme, aby bylo možné nastavit jméno, příjmení nebo celé jméno a aby se zbylá dvě automaticky aktualizovala.

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

Takže o co tu jde?

Klíčová slova get a set jsou důležitá. Následuje za nimi vlastnost, které se týkají (fullName), a tělo funkce, které definuje chování při přístupu k vlastnosti (name = person.fullName) nebo její změně (person.fullName = 'Some Name').

Tato dvě klíčová slova definují přístupové funkce: getter a setter pro vlastnost fullName. Při přístupu k vlastnosti se použije návratová hodnota z getteru. Při nastavování hodnoty se zavolá setter a předá se mu nastavená hodnota. Je na vás, co s touto hodnotou uděláte, ale to, co se vrátí z setteru, je hodnota, která byla předána – nemusíte tedy nic vracet.

Oficiální způsob: Object.defineProperty

Kromě inline způsobu deklarace getterů a setterů to lze provést také explicitněji pomocí Object.defineProperty (MDN dokumentace). Tato metoda přijímá tři argumenty. Prvním je objekt, ke kterému má být vlastnost přidána, druhým je název vlastnosti a třetím je objekt, který vlastnost popisuje (tzv. deskriptor vlastnosti). Zde je příklad, který kopíruje výše uvedený příklad:

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 || '';}});

Výhoda zde není hned patrná. Kromě možnosti přidávat vlastnosti po vytvoření počátečního objektu, je v tom nějaká skutečná výhoda?“

Když definujete vlastnost tímto způsobem, můžete udělat mnohem více než jen definovat setter nebo getter. Můžete také předat následující klíče:

  • configurable (false ve výchozím nastavení): pokud je to pravda, konfiguraci vlastnosti bude možné v budoucnu měnit.
  • enumerable (false ve výchozím nastavení): pokud je to pravda, vlastnost se zobrazí při procházení objektem (for (var key in obj)).

Můžeme také definovat vlastnosti, které nemají explicitní gettery nebo settery:

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

Tímto způsobem se vytvoří person.age a nastaví se na hodnotu 42. V případě, že se vytvoří person.age, nastaví se na hodnotu 42. Je důležité si uvědomit, že tato vlastnost není zapisovatelná. Volání person.age = 99 nebude mít žádný účinek. Tímto způsobem můžete vytvářet vlastnosti pouze pro čtení. Pokud má vlastnost nastavený klíč value, nemůže mít getter ani setter. Vlastnosti mohou mít hodnoty nebo accessory, ne obojí.

Nejen to, ale protože vlastnost enumerable má výchozí hodnotu false, tato vlastnost se nezobrazí, když procházíme smyčkou klíče objektu.

Pokud bychom chtěli, aby byla vlastnost zapisovatelná, museli bychom nastavit vlastnost writable:

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

Nyní bude mít person.age = 99; požadovaný účinek.

Používání nadměrné

Pamatujte: jen proto, že nějaká vlastnost existuje, nemusí se používat stále. Gettery a settery mají své využití, ale nepřehánějte to, jinak s největší pravděpodobností skončíte s návrhem, který bude pro ty, kdo s vašimi objekty komunikují, matoucí. Při opatrném použití jsou velmi účinné. S velkou mocí však přichází i velká zodpovědnost.

Podpora prohlížečů?

IE9 a vyšší mají plnou podporu Object.defineProperty, stejně jako Safari 5+, Firefox 4+, Chrome 5+ a Opera 12+. Pokud pracujete s Node.js, je zde plná podpora. Nemilujete prostě Node?“

Tento článek byl napsán společně s Tomem Ashworthem. Tomovi děkuji za pomoc při jeho sestavování.

Pokud se vám tento příspěvek líbil, přihlaste se k odběru novinek, abyste dostávali informace o novém obsahu 😎.

Všechny příspěvky na blogu

Pokud se vám tento příspěvek líbil, určitě mě sledujte na Twitteru.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.