Einfaches Anlegen von Objekten mit benutzerdefinierten Eigenschaften
- Debugger
({ Merkur: 1, Venus: 2, Erde: 3 }).Merkur // 1 //
({ Merkur: 1, Venus: 2, Erde: 3 }).Venus // 2 //
({ Merkur: 1, Venus: 2, Erde: 3 }).Erde // 3 //
let planet ={ Merkur:1, Venus: 2, Erde:3 }; // undefined //
planet.Merkur // 1 //
planet.Venus // 2 //
planet.Erde // 3 //
Das Anlegen eines Objekts durch eine kommagetrennte Aufzählung von Doppelpunkt-Definitionen in geschweiften Klammern reicht für einfache Anwendungsfälle aus.
In einer Definition wie »Merkur: 1« bezeichnen wir den linken Wert (das Definiendum) als „Schlüssel“ und den rechten Wert (das Definiens) als Wert. Man nennt »Merkur: 1« also auch ein „Schlüssel-Wert-Paar“ und kann sich so ein Objekt als eine Liste von Schlüssel-Wert-Paaren (also von Eigenschaften) vorstellen.
Es gibt jedoch Grenzen: So kann der Schlüssel (der Wert links vom Doppelpunkt) hierbei nur eine fester Text sein.
Im folgenden werden wir nun das kontrollierte Anlegen von Objekten zeigen, bei dem alle Details genau kontrolliert werden. Dies wird dazu führen, daß einige Details erkennbar werden, die nicht alle auf einmal erlernt werden können und sollen. Es hat aber den Vorteil, daß das Verhalten der Sprache damit genau beschrieben und erkannt werden kann. Es legt die Grundlage zum Verständnis der prototypbasierten JavaScript-Programmierung und erleichtert es dann, weitere in der Praxis übliche Arten der Gestaltung von Konstruktoren und Protoypen.
nicht {}.toString() sondern ({}).toString(), da eine Ausdruckskontext benötigt wird, um die geschweiften Klammern von einem Block zu unterscheiden.
Kontrolliertes Anlegen von Objekten mit benutzerdefinierten Einträgen
Zum Anlagen von Objekten gibt es in JavaScript tausendundeine Möglichkeit [Literaturhinweis: Nicholas C. Zakas: Professional Javascript® for Web Developers (2012), Chapter 6: Object-Oriented Programming], und jeder Lehrer muß sich fragen, welche davon er unterrichten soll, oder wenigstens: welche er zuerst unterrichten soll! In diesem Kurs wird dazu nun bewußt eine bestimmte Auswahl getroffen, von welcher der Autor glaubt, daß sie einen guten Kompromiß zwischen verschiedenen Anforderungen darstellt. Dennoch sollte der Leser sich nicht wundern, wenn er in anderen Quellen ganz andere Zugangswege dazu findet, auch diese haben sicher ihre Berechtigung. Aus Mangel an Zeit und um das Lernen zu erleichtern, sollen in diesem Kurs aber nicht alle verschiedenen Möglichkeiten vorgestellt werden. Eine reicht ja zunächst aus.
Wir zeigen zunächst einmal, wie man eine neues leeres Objekt ohne Prototyp erhält (Prototypen werden später erklärt werden, deswegen behandeln wird hier zunächst Objekte ohne Prototypen):
- Debugger
var counter = Object.create( null );
Normalerweise kann man »toString« über jedes Objekt aufrufen, aber nicht bei unserem »counter«: Da wir diesem absichtlich keinen Prototyp gegeben haben, ist er wirklich leer und enthält auch keine toString-Funktion!
- Konsole
counter.toString() // /// TypeError: counter.toString is not a function
Kontrolliertes Hinzufügen von Eigenschaften zu Objekten
Wir können zu dem Objekt empty nun Schlüssel mit Werten und weitere Konfigurationseigenschaften hinzufügen:
- Debugger
Object.defineProperty( counter, "v", { value: 27, configurable: true, enumerable: true, writable: true });
)Eine eventuelle Fehlermeldung »aResult.toString is not a function« ist in diesem kein Problem und kann ignoriert werden.)
Wir erkennen nun, daß zu einem Schlüssel nicht nur ein Wert gehört, sondern auch weitere Eigenschaften:
counter ist das Objekt, zu dem ein neuer Eintrag (eine Definition) hinzugefügt werden soll
"v" ist der Schlüssel des neuen Eintrags
27 ist der Wert des neuen Eintrags
Daneben gibt es Konfigurationseigenschaften:
configurable
legt fest, ob diese Konfigurationseigenschaften später verändert werden dürfen
enumerable
legt fest, ob dieser Eintrag beim Aufzählungen berücksichtigt werden soll
writable
legt fest, ob dieser Eintrag auf der linken Seite einer Zuweisung erlaubt ist (veränderbar ist)
Wir haben also oben in dem Objekt counter v als 27 definiert, wobei dieser Eintrag aufzählbar und sein Wert veränderbar ist, solange er nicht umkonfiguriert wird.
Die Definition von Einträgen mit defineProperty soll hier nicht unbedingt für die spätere Anwendung von JavaScript in der Praxis empfohlen werden. Sie ist aber zum Lernen gut geeignet, weil die Konfiguration dabei deutlich erkennbar wird.
Wir nenne ein Objekt, welches nur Daten, aber keine Funktion enthält ein reines Datenobjekt.
Schreibbarkeit
- Debugger
Object.defineProperty( counter, "a", { value: 27, configurable: true, enumerable: true, writable: true }); // /// TypeError: aResult.toString is not a function
counter.a = 8; // 8 //
counter.a // 8 //
Object.defineProperty( counter, "b", { value: 27, configurable: true, enumerable: true, writable: false }); // /// TypeError: aResult.toString is not a function
counter.b = 4; // 4 //
counter.b // 27 //
Aufzählbarkeit und for-in-Schleife
- Debugger
Object.defineProperty( counter, "c", { value: 27, configurable: true, enumerable: false, writable: true }); // /// TypeError: aResult.toString is not a function
for( let i in counter )console.log( i ); // undefined // v a b
Object.getOwnPropertyNames( counter ).toString() // v,a,b,c
PS Die for-in-Schleifen sind wohl veraltet (Stand 2018). Statt dessen sollten for-of-Schleifen verwendet werden.
Hinzufügen von Methoden zu Objekten (this)
- Debugger
Object.defineProperty( counter, "inc", { value: function(){ "use strict"; return this.v++; }, configurable: true, enumerable: false, writable: true });
counter.inc(); // 27 //
counter.inc(); // 28 //
counter.inc(); // 29 //
- Aufrufe mit .call( target )
create mit einem zweiten Argument
Object.create( null,
{ a: { value: 27 },
b: { value: 28 }})