JavaScript für ungeduldige Programmierer (ES2022-Ausgabe)
Bitte unterstützen Sie dieses Buch: kaufen Sie es oder spenden Sie
(Werbung, bitte nicht blockieren.)

12 Werte



In diesem Kapitel untersuchen wir, welche Arten von Werten JavaScript hat.

  Unterstützendes Werkzeug: ===

In diesem Kapitel werden wir gelegentlich den strikten Gleichheitsoperator verwenden. a === b ergibt true, wenn a und b gleich sind. Was genau das bedeutet, wird in §13.4.2 „Strikte Gleichheit (=== und !==)” erklärt.

12.1 Was ist ein Typ?

Für dieses Kapitel betrachte ich Typen als Mengen von Werten – beispielsweise ist der Typ boolean die Menge { false, true }.

12.2 JavaScripts Typenhierarchie

Figure 6: A partial hierarchy of JavaScript’s types. Missing are the classes for errors, the classes associated with primitive types, and more. The diagram hints at the fact that not all objects are instances of Object.

Abb. 6 zeigt die Typenhierarchie von JavaScript. Was lernen wir aus diesem Diagramm?

12.3 Die Typen der Sprachspezifikation

Die ECMAScript-Spezifikation kennt nur insgesamt acht Typen. Die Namen dieser Typen sind (ich verwende die Namen von TypeScript, nicht die Namen der Spezifikation)

12.4 Primitive Werte vs. Objekte

Die Spezifikation macht eine wichtige Unterscheidung zwischen Werten

Im Gegensatz zu Java (das JavaScript hier inspiriert hat) sind primitive Werte keine Bürger zweiter Klasse. Der Unterschied zwischen ihnen und Objekten ist subtiler. Kurz gesagt

Abgesehen davon sind primitive Werte und Objekte ziemlich ähnlich: Sie haben beide Eigenschaften (Schlüssel-Wert-Einträge) und können an denselben Stellen verwendet werden.

Als Nächstes werden wir primitive Werte und Objekte eingehender betrachten.

12.4.1 Primitive Werte (kurz: Primitiven)

12.4.1.1 Primitive sind unveränderlich

Sie können keine Eigenschaften von Primitiven ändern, hinzufügen oder entfernen

const str = 'abc';
assert.equal(str.length, 3);
assert.throws(
  () => { str.length = 1 },
  /^TypeError: Cannot assign to read only property 'length'/
);
12.4.1.2 Primitive werden per Wert übergeben

Primitive werden per Wert übergeben: Variablen (einschließlich Parameter) speichern die Inhalte der Primitiven. Wenn ein primitiver Wert einer Variablen zugewiesen oder als Argument an eine Funktion übergeben wird, wird sein Inhalt kopiert.

const x = 123;
const y = x;
// `y` is the same as any other number 123
assert.equal(y, 123);

  Beobachtung des Unterschieds zwischen Übergabe per Wert und Übergabe per Referenz

Aufgrund der Tatsache, dass primitive Werte unveränderlich sind und nach Wert verglichen werden (siehe nächster Unterabschnitt), gibt es keine Möglichkeit, den Unterschied zwischen Übergabe per Wert und Übergabe per Identität (wie sie für Objekte in JavaScript verwendet wird) zu beobachten.

12.4.1.3 Primitive werden nach Wert verglichen

Primitive werden nach Wert verglichen: Beim Vergleichen zweier primitiver Werte vergleichen wir ihre Inhalte.

assert.equal(123 === 123, true);
assert.equal('abc' === 'abc', true);

Um zu sehen, was an dieser Vergleichsweise so besonders ist, lesen Sie weiter und erfahren Sie, wie Objekte verglichen werden.

12.4.2 Objekte

Objekte werden ausführlich in §28 „Objekte“ und im folgenden Kapitel behandelt. Hier konzentrieren wir uns hauptsächlich darauf, wie sie sich von primitiven Werten unterscheiden.

Lassen Sie uns zuerst zwei gängige Möglichkeiten zur Erstellung von Objekten untersuchen

12.4.2.1 Objekte sind standardmäßig veränderlich

Standardmäßig können Sie die Eigenschaften von Objekten frei ändern, hinzufügen und entfernen

const obj = {};

obj.count = 2; // add a property
assert.equal(obj.count, 2);

obj.count = 3; // change a property
assert.equal(obj.count, 3);
12.4.2.2 Objekte werden per Identität übergeben

Objekte werden per Identität übergeben (mein Begriff): Variablen (einschließlich Parameter) speichern die Identitäten von Objekten.

Die Identität eines Objekts ist wie ein Zeiger (oder eine transparente Referenz) auf die tatsächlichen Daten des Objekts im Heap (denken Sie an den gemeinsamen Hauptspeicher einer JavaScript-Engine).

Beim Zuweisen eines Objekts zu einer Variablen oder beim Übergeben als Argument an eine Funktion wird seine Identität kopiert. Jedes Objektliteral erstellt ein neues Objekt im Heap und gibt seine Identität zurück.

const a = {}; // fresh empty object
// Pass the identity in `a` to `b`:
const b = a;

// Now `a` and `b` point to the same object
// (they “share” that object):
assert.equal(a === b, true);

// Changing `a` also changes `b`:
a.name = 'Tessa';
assert.equal(b.name, 'Tessa');

JavaScript verwendet Garbage Collection zur automatischen Speicherverwaltung

let obj = { prop: 'value' };
obj = {};

Nun ist der alte Wert { prop: 'value' } von obj Müll (wird nicht mehr verwendet). JavaScript wird ihn automatisch garbage-collecten (aus dem Speicher entfernen), zu einem bestimmten Zeitpunkt (möglicherweise nie, wenn genügend freier Speicher vorhanden ist).

  Details: Übergabe per Identität

„Übergabe per Identität“ bedeutet, dass die Identität eines Objekts (eine transparente Referenz) per Wert übergeben wird. Dieser Ansatz wird auch als „Übergabe durch Teilen“ bezeichnet.

12.4.2.3 Objekte werden nach Identität verglichen

Objekte werden nach Identität verglichen (mein Begriff): Zwei Variablen sind nur dann gleich, wenn sie die gleiche Objektidentität enthalten. Sie sind nicht gleich, wenn sie auf unterschiedliche Objekte mit demselben Inhalt verweisen.

const obj = {}; // fresh empty object
assert.equal(obj === obj, true); // same identity
assert.equal({} === {}, false); // different identities, same content

12.5 Die Operatoren typeof und instanceof: Was ist der Typ eines Wertes?

Die beiden Operatoren typeof und instanceof ermöglichen es Ihnen festzustellen, welchen Typ ein gegebener Wert x hat

if (typeof x === 'string') ···
if (x instanceof Array) ···

Wie unterscheiden sie sich?

  Faustregel: typeof ist für primitive Werte; instanceof ist für Objekte

12.5.1 typeof

Tabelle 2: Die Ergebnisse des typeof-Operators.
x typeof x
undefined 'undefined'
null 'object'
Boolean 'boolean'
Number 'number'
Bigint 'bigint'
String 'string'
Symbol 'symbol'
Funktion 'function'
Alle anderen Objekte 'object'

Tabelle 2 listet alle Ergebnisse von typeof auf. Sie entsprechen ungefähr den 7 Typen der Sprachspezifikation. Leider gibt es zwei Unterschiede, und das sind Sprachquirks

Dies sind einige Beispiele für die Verwendung von typeof

> typeof undefined
'undefined'
> typeof 123n
'bigint'
> typeof 'abc'
'string'
> typeof {}
'object'

  Übungen: Zwei Übungen zu typeof

12.5.2 instanceof

Dieser Operator beantwortet die Frage: Wurde ein Wert x von einer Klasse C erzeugt?

x instanceof C

Zum Beispiel

> (function() {}) instanceof Function
true
> ({}) instanceof Object
true
> [] instanceof Array
true

Primitive Werte sind keine Instanzen von irgendetwas

> 123 instanceof Number
false
> '' instanceof String
false
> '' instanceof Object
false

  Übung: instanceof

exercises/values/instanceof_exrc.mjs

12.6 Klassen und Konstruktorfunktionen

JavaScripts ursprüngliche Fabriken für Objekte sind Konstruktorfunktionen: gewöhnliche Funktionen, die „Instanzen“ von sich selbst zurückgeben, wenn sie mit dem Operator new aufgerufen werden.

ES6 führte Klassen ein, die hauptsächlich eine bessere Syntax für Konstruktorfunktionen sind.

In diesem Buch verwende ich die Begriffe Konstruktorfunktion und Klasse austauschbar.

Klassen können als eine Partitionierung des einzelnen Typs object der Spezifikation in Untertypen betrachtet werden – sie geben uns mehr Typen als die begrenzten 7 Typen der Spezifikation. Jede Klasse ist der Typ der Objekte, die von ihr erstellt wurden.

12.6.1 Konstruktorfunktionen, die mit primitiven Typen assoziiert sind

Jeder primitive Typ (außer den internen Typen der Spezifikation für undefined und null) hat eine zugeordnete Konstruktorfunktion (denken Sie an Klasse)

Jede dieser Funktionen spielt mehrere Rollen – zum Beispiel Number

12.6.1.1 Primitive Werte wrappen

Die Konstruktorfunktionen, die mit primitiven Typen zusammenhängen, werden auch als Wrapper-Typen bezeichnet, da sie den kanonischen Weg zur Konvertierung primitiver Werte in Objekte bieten. Dabei werden primitive Werte in Objekte „gewrappt“.

const prim = true;
assert.equal(typeof prim, 'boolean');
assert.equal(prim instanceof Boolean, false);

const wrapped = Object(prim);
assert.equal(typeof wrapped, 'object');
assert.equal(wrapped instanceof Boolean, true);

assert.equal(wrapped.valueOf(), prim); // unwrap

Das Wrapping spielt in der Praxis selten eine Rolle, wird aber intern in der Sprachspezifikation verwendet, um Primitiven Eigenschaften zu geben.

12.7 Konvertierung zwischen Typen

Es gibt zwei Möglichkeiten, wie Werte in JavaScript in andere Typen konvertiert werden

12.7.1 Explizite Konvertierung zwischen Typen

Die Funktion, die mit einem primitiven Typ assoziiert ist, konvertiert Werte explizit in diesen Typ

> Boolean(0)
false
> Number('123')
123
> String(123)
'123'

Sie können auch Object() verwenden, um Werte in Objekte zu konvertieren

> typeof Object(123)
'object'

Die folgende Tabelle beschreibt detaillierter, wie diese Konvertierung funktioniert

x Object(x)
undefined {}
null {}
boolean new Boolean(x)
number new Number(x)
bigint Eine Instanz von BigInt (new wirft TypeError)
string new String(x)
symbol Eine Instanz von Symbol (new wirft TypeError)
object x

12.7.2 Coercion (automatische Konvertierung zwischen Typen)

Bei vielen Operationen konvertiert JavaScript die Operanden/Parameter automatisch, wenn ihre Typen nicht passen. Diese Art der automatischen Konvertierung wird Coercion genannt.

Zum Beispiel konvertiert der Multiplikationsoperator seine Operanden in Zahlen

> '7' * '3'
21

Viele integrierte Funktionen führen ebenfalls Coercion durch. Zum Beispiel konvertiert Number.parseInt() seinen Parameter vor dem Parsen in eine Zeichenkette. Das erklärt folgendes Ergebnis

> Number.parseInt(123.45)
123

Die Zahl 123.45 wird in die Zeichenkette '123.45' konvertiert, bevor sie geparst wird. Das Parsen stoppt vor dem ersten Nicht-Ziffern-Zeichen, weshalb das Ergebnis 123 ist.

  Übung: Werte in Primitive konvertieren

exercises/values/conversion_exrc.mjs

  Quiz

Siehe Quiz-App.