Dezember 23, 2013
Das meiste in JavaScript ist, was man sieht, was man bekommt. Ein Wert ist ein Wert, da gibt es keine Tricks. Manchmal möchte man jedoch einen Wert, der auf anderen Werten basiert: Der vollständige Name einer Person ist zum Beispiel eine Verkettung von Vor- und Nachnamen. Wenn Sie ein person
-Objekt haben und möchten, dass die Benutzer dieses Objekts in der Lage sind, den vollständigen Vor- oder Nachnamen zu setzen und diese Änderung sofort in den anderen Werten widergespiegelt zu sehen, würden Sie es konventionell mit Funktionen aufbauen:
person.setLastName('Smith');person.setFirstName('Jimmy');person.getFullName(); // Jimmy Smith
Aber das ist hässlich und erfordert, dass die Benutzer Ihres Objekts sich darum kümmern, dass die Eigenschaften miteinander verbunden sind; in einem komplexeren Beispiel ist das vielleicht nicht so offensichtlich wie bei Namen. Glücklicherweise gibt es einen besseren Weg, der in ECMAScript 5 hinzugefügt wurde.
Mit Gettern und Settern.
Wie
Lassen Sie uns dieses Personenobjekt erstellen. Wir wollen in der Lage sein, den Vornamen, den Nachnamen oder den vollständigen Namen zu setzen und die anderen beiden automatisch zu aktualisieren.
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
Was ist hier los?
Die Schlüsselwörter get und set sind wichtig. Nach ihnen folgt die Eigenschaft, auf die sie sich beziehen (fullName
), und ein Funktionskörper, der das Verhalten definiert, wenn auf die Eigenschaft zugegriffen (name = person.fullName
) oder sie geändert wird (person.fullName = 'Some Name'
).
Diese beiden Schlüsselwörter definieren Accessor-Funktionen: einen Getter und einen Setter für die Eigenschaft fullName
. Wenn auf die Eigenschaft zugegriffen wird, wird der Rückgabewert des Getters verwendet. Wenn ein Wert gesetzt wird, wird der Setter aufgerufen und der Wert, der gesetzt wurde, übergeben. Es liegt an Ihnen, was Sie mit diesem Wert machen, aber was vom Setter zurückgegeben wird, ist der Wert, der übergeben wurde – Sie müssen also nichts zurückgeben.
Der offizielle Weg: Object.defineProperty
Neben der Inline-Methode zur Deklaration von Gettern und Settern kann dies auch expliziter über Object.defineProperty
(MDN-Dokumentation) erfolgen. Diese Methode nimmt drei Argumente entgegen. Das erste ist das Objekt, dem die Eigenschaft hinzugefügt werden soll, das zweite ist der Name der Eigenschaft, und das dritte ist ein Objekt, das die Eigenschaft beschreibt (der so genannte Deskriptor der Eigenschaft). Hier ist ein Beispiel, das das obige Beispiel wiederholt:
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 || '';}});
Der Vorteil ist nicht sofort ersichtlich. Gibt es außer der Möglichkeit, Eigenschaften nach der Erstellung des ursprünglichen Objekts hinzuzufügen, einen wirklichen Vorteil?
Wenn Sie eine Eigenschaft auf diese Weise definieren, können Sie viel mehr tun als nur einen Setter oder Getter zu definieren. Sie können auch folgende Schlüssel übergeben:
-
configurable
(false
standardmäßig): wenn dies wahr ist, kann die Konfiguration der Eigenschaft in Zukunft geändert werden. -
enumerable
(false
standardmäßig): wenn dies wahr ist, wird die Eigenschaft beim Überfahren des Objekts angezeigt (for (var key in obj)
).
Wir können auch Eigenschaften definieren, die keine expliziten Getter oder Setter haben:
Object.defineProperty(person, 'age', { value: 42});
Dies erzeugt person.age
und setzt es auf den Wert 42. Es ist wichtig zu beachten, dass diese Eigenschaft nicht beschreibbar ist. Der Aufruf von person.age = 99
hat keine Auswirkung. Auf diese Weise können Sie schreibgeschützte Eigenschaften erstellen. Wenn eine Eigenschaft einen value
-Schlüssel gesetzt hat, kann sie keinen Getter oder Setter haben. Eigenschaften können Werte oder Accessoren haben, nicht beides.
Nicht nur das, sondern weil die enumerable
-Eigenschaft standardmäßig auf false
eingestellt ist, wird diese Eigenschaft nicht angezeigt, wenn wir eine Schleife über die Schlüssel des Objekts ziehen.
Wenn wir eine Eigenschaft beschreibbar machen wollten, müssten wir die writable
-Eigenschaft einstellen:
Object.defineProperty(person, 'age', { value: 42, writable: true});
Jetzt hat person.age = 99;
den gewünschten Effekt.
Überbeanspruchung
Erinnern Sie sich: Nur weil eine Funktion existiert, muss sie nicht immer verwendet werden. Getter und Setter haben ihre Berechtigung, aber übertreiben Sie es nicht, sonst werden Sie wahrscheinlich mit einem Design enden, das für diejenigen, die mit Ihren Objekten interagieren, verwirrend ist. Sorgfältig eingesetzt, sind sie sehr mächtig. Aber mit großer Macht kommt große Verantwortung.
Browserunterstützung?
IE9 und höher haben volle Unterstützung für Object.defineProperty
, zusammen mit Safari 5+, Firefox 4+, Chrome 5+ und Opera 12+. Wenn du mit Node.js arbeitest, gibt es volle Unterstützung. Lieben Sie Node nicht auch?
Dieser Artikel wurde gemeinsam mit Tom Ashworth verfasst. Vielen Dank an Tom für seine Hilfe bei der Zusammenstellung dieses Artikels.
Wenn Ihnen dieser Beitrag gefallen hat, melden Sie sich für den Newsletter an, um über neue Inhalte informiert zu werden 😎.
Alle Blogbeiträge
Wenn Ihnen dieser Beitrag gefallen hat, sollten Sie mir auf Twitter folgen.