Читать книгу JavaScript – Das Handbuch für die Praxis - David Flanagan - Страница 51
3.8Unveränderbare primitive Werte und veränderbare Objektreferenzen
ОглавлениеEs gibt in JavaScript einen grundlegenden Unterschied zwischen primitiven Werten (undefined, null, boolesche Werte, Zahlen und Zeichenketten) und Objekten (einschließlich Arrays und Funktionen). Primitive Werte sind immutabel: Es gibt keine Möglichkeit, sie zu verändern. Bei Zahlen und booleschen Werten ist das offensichtlich – schon die Vorstellung, den Wert einer Zahl zu ändern, ist sinnlos. Bei Strings hingegen ist das nicht ganz so offensichtlich. Da Strings Arrays von Zeichen ähneln, mag man vermuten, Zeichen an einer bestimmten Indexposition könne man ändern. JavaScript gestattet das aber nicht, und alle String-Methoden, die einen veränderten String zu liefern scheinen, liefern tatsächlich einen neuen String-Wert, zum Beispiel:
let s = "hello"; // Beginnen wir mit einem Text in Kleinbuchstaben.
s.toUpperCase(); // Gibt "HELLO" zurück, verändert s aber nicht.
s // => "hello": Der ursprüngliche String hat sich nicht geändert.
Primitive Typen werden außerdem anhand ihres Werts (by value) verglichen: Zwei Werte sind nur dann gleich, wenn sie den gleichen Wert haben. Für Zahlen, boolesche Werte, null und undefined scheint das zirkulär zu klingen: Auf andere Weise könnten Werte dieser Art gar nicht verglichen werden. Aber auch das ist bei Strings nicht ganz so selbstverständlich. Wenn zwei unterschiedliche String-Werte verglichen werden, behandelt JavaScript diese nur dann als gleich, wenn sie die gleiche Länge haben und die einzelnen Zeichen an den einzelnen Indexpositionen gleich sind.
Objekte unterscheiden sich von primitiven Datentypen. Erstens sind sie mutabel – ihre Werte können sich ändern:
let o = { x: 1 }; // Beginnen wir mit einem Objekt.
o.x = 2; // Verändern wir es, indem wir den Wert einer Eigenschaft
// ändern.
o.y = 3; // Verändern wir es erneut, indem wir ihm eine Eigenschaft
// hinzufügen.
let a = [1,2,3]; // Arrays sind ebenfalls veränderbar.
a[0] = 0; // Den Wert eines Array-Elements ändern.
a[3] = 4; // Ein neues Array-Element einfügen.
Zweitens werden Objekte nicht anhand des Werts verglichen: Zwei Objekte sind nicht allein deswegen gleich, weil sie die gleichen Eigenschaften und Werte haben. Und zwei Arrays sind nicht allein deswegen gleich, weil sie die gleichen Elemente in der gleichen Reihenfolge aufweisen:
let o = {x: 1}, p = {x: 1}; // Zwei Objekte mit den gleichen Eigenschaften.
o === p // => false: Zwei verschiedene Objekte sind nie gleich.
let a = [], b = []; // Zwei Arrays, beide leer.
a === b // => false: Zwei verschiedene Arrays sind nie gleich.
Objekte werden manchmal auch als Referenztypen bezeichnet, um sie von JavaScripts primitiven Datentypen abzugrenzen. Legt man diese Terminologie zugrunde, sind die Werte von Objekten Referenzen, und wir können auch sagen, dass Objekte anhand der Referenz (by reference) verglichen werden: Zwei Objektwerte sind nur dann gleich, wenn sie auf dasselbe zugrunde liegende Objekt verweisen.
let a = []; // Die Variable a verweist auf ein leeres Array.
let b = a; // Jetzt verweist b auf dasselbe Array.
b[0] = 1; // Verändert das Array, auf das die Variable b verweist.
a[0] // => 1: Die Änderung ist auch über die Variable a sichtbar.
a === b // => true: a und b verweisen auf dasselbe Objekt, sind also gleich.
Wie der Beispielcode zeigt, wird bei der Zuweisung eines Objekts (oder Arrays) an eine Variable einfach eine Referenz zugewiesen; dabei wird kein neues Exemplar des Objekts erstellt. Wollen Sie eine Kopie eines Objekts oder Arrays erstellen, müssen Sie explizit die Eigenschaften des Objekts oder die Elemente des Arrays kopieren. Das folgende Beispiel zeigt, wie man das mit einer for-Schleife macht (siehe 5.4.3):
let a = ["a","b","c"]; // Das Array, das wir kopieren wollen.
let b = []; // Ein neues Array, in das wir kopieren werden.
for(let i = 0; i < a.length; i++) { // Für jede Indexposition in a[]:
b[i] = a[i]; // Kopiere ein Element von a in b.
}
let c = Array.from(b); // In ES6 kopieren Sie Arrays mit Array.from().
Gleichermaßen müssen wir, wenn wir zwei eigenständige Objekte oder Arrays vergleichen wollen, einzeln ihre Eigenschaften oder Elemente vergleichen. Der folgende Code definiert eine Funktion zum Vergleich von zwei Arrays:
function equalArrays(a, b) {
if (a === b) return true; // Identische Arrays sind gleich.
if (a.length !== b.length) return false; // Arrays unterschiedlicher Länge
// sind nicht gleich.
for(let i = 0; i < a.length; i++) { // Alle Elemente durchlaufen:
if (a[i] !== b[i]) return false; // Ist ein Elementpaar nicht gleich,
// sind die Arrays nicht gleich.
}
return true; // Andernfalls sind die Arrays gleich.
}