December 23, 2013
A JavaScriptben többnyire azt kapod, amit látsz. Az érték az érték, nincsenek trükkök. Néha azonban olyan értéket akarsz, amely más értékeken alapul: valakinek a teljes neve például a kereszt- és vezetéknevének az összevonásából áll. Ha van egy person
objektumod, és azt akarod, hogy az objektum felhasználói beállíthassák a teljes, kereszt- vagy vezetéknevet, és a változás azonnal tükröződjön a többi értékben, akkor ezt konvencionálisan függvényekkel építenéd fel:
person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith
De ez csúnya, és megköveteli, hogy az objektumod felhasználói törődjenek azzal, hogy a tulajdonságok kapcsolatban vannak egymással; egy összetettebb példában ez nem biztos, hogy olyan nyilvánvaló, mint a nevek esetében. Szerencsére van egy jobb módszer, amely az ECMAScript 5-ben került bele.
Találkozzunk a getterekkel és setterekkel.
Hogyan
Készítsük el azt a személy objektumot. Szeretnénk, ha beállíthatnánk a keresztnevet, a vezetéknevet vagy a teljes nevet, és a másik kettőt automatikusan frissítené.
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
Mi történik itt?
A get és set kulcsszavak fontosak. Utánuk következik a tulajdonság, amelyre vonatkoznak (fullName
) és egy függvénytest, amely meghatározza a viselkedést a tulajdonság elérésekor (name = person.fullName
) vagy módosításakor (person.fullName = 'Some Name'
).
Ez a két kulcsszó hozzáférési függvényeket definiál: egy getter és egy setter a fullName
tulajdonsághoz. A tulajdonság elérésekor a getter visszatérési értéke kerül felhasználásra. Az érték beállításakor a setter meghívásra kerül, és a beállított értéket adja át. Rajtad múlik, hogy mit kezdesz ezzel az értékkel, de a setter által visszaadott érték az átadott érték – tehát nem kell semmit sem visszaadnod.
A hivatalos út: Object.defineProperty
A getterek és setterek deklarálásának inline módszere mellett explicit módon is megtehetjük Object.defineProperty
(MDN dokumentáció). Ez a módszer három argumentumot fogad el. Az első a tulajdonságot hozzáadni kívánt objektum, a második a tulajdonság neve, a harmadik pedig a tulajdonságot leíró objektum (az úgynevezett tulajdonság leírója). Íme egy példa, amely megismétli a fenti példát:
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 || '';}});
Az előny itt nem látszik azonnal. Azon kívül, hogy a kezdeti objektum létrehozása után tudunk tulajdonságokat hozzáadni, van-e valódi előnye?
Ha így definiálunk egy tulajdonságot, sokkal többet tehetünk, mint egy setter vagy getter definiálása. A következő kulcsokat is átadhatjuk:
-
configurable
(alapértelmezés szerintfalse
): ha ez igaz, akkor a tulajdonság beállítása a jövőben módosítható lesz. -
enumerable
(alapértelmezés szerintfalse
): ha igaz, akkor a tulajdonság megjelenik az objektumon való átfutáskor (for (var key in obj)
).
Meghatározhatunk olyan tulajdonságokat is, amelyeknek nincs explicit getterük vagy setterük:
Object.defineProperty(person, 'age', { value: 42});
Ez létrehozza a person.age
tulajdonságot, és a 42-es értékre állítja. Fontos megjegyezni, hogy ez a tulajdonság nem írható. A person.age = 99
meghívásának nincs hatása. Ily módon csak olvasható tulajdonságokat hozhatunk létre. Ha egy tulajdonságnak value
kulcs van beállítva, akkor nem lehet gettere vagy settere. A tulajdonságoknak csak értékei vagy hozzáférői lehetnek, mindkettő nem.
Nem csak ez, hanem mivel a enumerable
tulajdonság alapértelmezett értéke false
, ez a tulajdonság nem fog megjelenni, amikor az objektum kulcsain végighaladunk.
Ha írhatóvá akarnánk tenni egy tulajdonságot, akkor a writable
tulajdonságot kellene beállítanunk:
Object.defineProperty(person, 'age', { value: 42, writable: true});
Most a person.age = 99;
fogja elérni a kívánt hatást.
Túlhasználat
Ne feledjük: csak azért, mert egy tulajdonság létezik, nem kell mindig használni. A Gettereknek és Settereknek megvannak a maguk felhasználási esetei, de ne essünk túlzásba, különben valószínűleg olyan dizájnnal fogunk végezni, amely zavaró az objektumokkal interakcióba lépők számára. Óvatosan használva nagyon erősek. De a nagy hatalommal nagy felelősség is jár.
Böngészőtámogatás?
Az IE9 és a magasabb verziószámok teljes mértékben támogatják a Object.defineProperty
, valamint a Safari 5+, Firefox 4+, Chrome 5+ és Opera 12+. Ha Node.js-szel dolgozol, akkor teljes támogatás van. Hát nem imádod a Node-ot?!”
Ez a cikk Tom Ashworth-tal közösen íródott. Köszönöm Tomnak a segítségét az összeállításban.
Ha tetszett ez a bejegyzés, iratkozz fel a hírlevélre, hogy értesülj az új tartalmakról 😎.
Minden blogbejegyzés
Ha tetszett ez a bejegyzés, kövess engem a Twitteren.