Das Material, dessen Übersetzung wir heute veröffentlichen, ist dem Studium von Objekten gewidmet - einer der Schlüsselessenzen von JavaScript. Es richtet sich in erster Linie an Anfänger, die ihr Wissen über Objekte optimieren möchten.

Objekte in JavaScript sind dynamische Sammlungen von Eigenschaften, die zusätzlich eine „versteckte“ Eigenschaft enthalten, die ein Prototyp des Objekts ist. Eigenschaften von Objekten sind durch Schlüssel und Werte gekennzeichnet. Beginnen wir die Konversation über JS-Objekte mit Schlüsseln.
Objekteigenschaftsschlüssel
Der Objekteigenschaftsschlüssel ist eine eindeutige Zeichenfolge. Sie können zwei Methoden verwenden, um auf Eigenschaften zuzugreifen: Zugriff über einen Punkt und Angabe des Objektschlüssels in eckigen Klammern. Beim Zugriff auf Eigenschaften über einen Punkt muss der Schlüssel eine gültige JavaScript-Kennung sein. Betrachten Sie ein Beispiel:
let obj = { message : "A message" } obj.message //"A message" obj["message"] //"A message"
Beim Versuch, auf eine nicht vorhandene Eigenschaft eines Objekts zuzugreifen, wird keine Fehlermeldung angezeigt, aber der
undefined
Wert wird zurückgegeben:
obj.otherProperty
Wenn Sie in eckigen Klammern auf Eigenschaften zugreifen, können Sie Schlüssel verwenden, die keine gültigen JavaScript-Bezeichner sind (der Schlüssel kann beispielsweise eine Zeichenfolge sein, die Leerzeichen enthält). Sie können einen beliebigen Wert haben, der in eine Zeichenfolge umgewandelt werden kann:
let french = {}; french["merci beaucoup"] = "thank you very much"; french["merci beaucoup"];
Wenn Nicht-String-Werte als Schlüssel verwendet werden, werden sie automatisch in Strings konvertiert (wenn möglich mit der
toString()
-Methode):
et obj = {}; //Number obj[1] = "Number 1"; obj[1] === obj["1"]; //true //Object let number1 = { toString : function() { return "1"; } } obj[number1] === obj["1"]; //true
In diesem Beispiel wird das Objekt
number1
als Schlüssel verwendet. Beim Versuch, auf eine Eigenschaft zuzugreifen, wird diese in Zeile
1
konvertiert, und das Ergebnis dieser Konvertierung wird als Schlüssel verwendet.
Objekteigenschaftswerte
Objekteigenschaften können primitive Werte, Objekte oder Funktionen sein.
▍Objekt als Objekteigenschaftswert
Objekte können in anderen Objekten platziert werden. Betrachten Sie
ein Beispiel :
let book = { title : "The Good Parts", author : { firstName : "Douglas", lastName : "Crockford" } } book.author.firstName;
Ein ähnlicher Ansatz kann zum Erstellen von Namespaces verwendet werden:
let app = {}; app.authorService = { getAuthors : function() {} }; app.bookService = { getBooks : function() {} };
▍ Funktion als Objekteigenschaftswert
Wenn eine Funktion als Objekteigenschaftswert verwendet wird, wird sie normalerweise zu einer Objektmethode. Verwenden Sie in der Methode das
this
, um auf das aktuelle Objekt zuzugreifen.
Dieses Schlüsselwort kann jedoch je nach Aufruf der Funktion unterschiedliche Bedeutungen haben.
Hier können Sie über Situationen lesen, in denen
this
den Kontext verliert.
Die Dynamik von Objekten
Objekte in JavaScript sind von Natur aus dynamische Entitäten. Sie können ihnen jederzeit Eigenschaften hinzufügen. Gleiches gilt für das Löschen von Eigenschaften:
let obj = {}; obj.message = "This is a message"; // obj.otherMessage = "A new message"; // delete obj.otherMessage; //
Objekte als assoziative Arrays
Objekte können als assoziative Arrays betrachtet werden. Assoziative Array-Schlüssel sind die Eigenschaftsnamen des Objekts. Um auf den Schlüssel zuzugreifen, müssen Sie nicht alle Eigenschaften betrachten, dh der Vorgang des Zugriffs auf den Schlüssel eines assoziativen Arrays basierend auf einem Objekt wird in O (1) -Zeit ausgeführt.
Objektprototypen
Objekte haben einen "versteckten" Link,
__proto__
, der auf ein Prototypobjekt verweist, von dem das Objekt Eigenschaften erbt.
Ein mit einem Objektliteral erstelltes Objekt verfügt beispielsweise über einen Link zu
Object.prototype
:
var obj = {}; obj.__proto__ === Object.prototype;
▍ Leere Objekte
Wie wir gerade gesehen haben, ist das "leere" Objekt
{}
tatsächlich nicht so leer, da es einen Verweis auf
Object.prototype
. Um ein wirklich leeres Objekt zu erstellen, müssen Sie die folgende Konstruktion verwenden:
Object.create(null)
Dadurch wird ein Objekt ohne Prototyp erstellt. Solche Objekte werden normalerweise verwendet, um assoziative Arrays zu erstellen.
▍ Prototypkette
Prototypobjekte können eigene Prototypen haben. Wenn Sie versuchen, auf eine Eigenschaft eines Objekts zuzugreifen, das sich nicht darin befindet, versucht JavaScript, diese Eigenschaft im Prototyp dieses Objekts zu finden. Wenn die gewünschte Eigenschaft nicht vorhanden ist, wird versucht, sie im Prototyp des Prototyps zu finden. Dies wird fortgesetzt, bis die gewünschte Eigenschaft gefunden wurde oder bis das Ende der Prototypkette erreicht ist.
Primitive Typwerte und Objektverpackungen
Mit JavaScript können Sie mit den Werten primitiver Typen als Objekte arbeiten, in dem Sinne, dass Sie mit der Sprache auf deren Eigenschaften und Methoden zugreifen können.
(1.23).toFixed(1); //"1.2" "text".toUpperCase(); //"TEXT" true.toString(); //"true"
Darüber hinaus sind die Werte primitiver Typen natürlich keine Objekte.
Um den Zugriff auf die „Eigenschaften“ von Werten primitiver Typen zu organisieren, erstellt JavaScript bei Bedarf Wrapper-Objekte, die, nachdem sie nicht mehr benötigt werden, zerstört werden. Der Prozess zum Erstellen und Zerstören von Wrapper-Objekten wird von der JS-Engine optimiert.
Objekt-Wrapper haben Werte vom numerischen, Zeichenfolgen- und logischen Typ. Objekte der entsprechenden Typen werden durch die Konstruktorfunktionen
Number
,
String
und
Boolean
.
Eingebettete Prototypen
Number-Objekte erben Eigenschaften und Methoden vom Prototyp
Number.prototype
, dem Nachkommen von
Object.prototype
:
var no = 1; no.__proto__ === Number.prototype; //true no.__proto__.__proto__ === Object.prototype; //true
Der Prototyp von String-Objekten ist
String.prototype
. Der Prototyp von booleschen Objekten ist
Boolean.prototype
. Der Prototyp von Arrays (die auch Objekte sind) ist
Array.prototype
.
Funktionen in JavaScript sind auch Objekte mit einem Prototyp
Function.prototype
. Funktionen haben Methoden wie
bind()
,
apply()
und
call()
.
Alle Objekte, Funktionen und Objekte, die primitive
Object.prototype
(mit Ausnahme von
null
und
undefined
Werten), erben Eigenschaften und Methoden von
Object.prototype
. Dies führt dazu, dass beispielsweise alle eine
toString()
-Methode haben.
Erweitern eingebetteter Objekte mit Polyfills
Mit JavaScript können eingebettete Objekte mithilfe sogenannter Polyfills problemlos um neue Funktionen erweitert werden. Eine Polyfüllung ist ein Code, der Funktionen implementiert, die von keinem Browser unterstützt werden.
▍Verwendung von Polyfills
Beispielsweise gibt es eine
Polyfüllung für die
Object.assign()
-Methode. Sie können dem
Object
eine neue Funktion hinzufügen, wenn diese nicht verfügbar ist.
Gleiches gilt für das
Array.from()
, das, wenn sich die
from()
-Methode nicht im
Array
Objekt befindet, mit dieser Methode ausgestattet wird.
▍ Polyfill und Prototypen
Mit Hilfe von Polyfills können Prototypen von Objekten um neue Methoden erweitert werden. Mit der
String.prototype.trim()
für
String.prototype.trim()
können Sie beispielsweise alle String-Objekte mit der Methode
trim()
ausstatten:
let text = " A text "; text.trim(); //"A text"
Mit der Array.prototype.find()
für
Array.prototype.find()
können Sie alle Arrays mit der
find()
-Methode ausstatten. Die
Array.prototype.findIndex()
für
Array.prototype.findIndex()
funktioniert auf ähnliche Weise:
let arr = ["A", "B", "C", "D", "E"]; arr.indexOf("C");
Einzelvererbung
Mit dem Befehl
Object.create()
können Sie neue Objekte mit einem bestimmten Prototypobjekt erstellen. Dieser Befehl wird in JavaScript verwendet, um einen einzelnen Vererbungsmechanismus zu implementieren. Betrachten Sie
ein Beispiel :
let bookPrototype = { getFullTitle : function(){ return this.title + " by " + this.author; } } let book = Object.create(bookPrototype); book.title = "JavaScript: The Good Parts"; book.author = "Douglas Crockford"; book.getFullTitle();
Mehrfachvererbung
Der Befehl
Object.assign()
kopiert Eigenschaften von einem oder mehreren Objekten in das Zielobjekt. Es kann verwendet werden, um mehrere Vererbungsschemata zu implementieren. Hier ist
ein Beispiel :
let authorDataService = { getAuthors : function() {} }; let bookDataService = { getBooks : function() {} }; let userDataService = { getUsers : function() {} }; let dataService = Object.assign({}, authorDataService, bookDataService, userDataService ); dataService.getAuthors(); dataService.getBooks(); dataService.getUsers();
Unveränderliche Objekte
Mit dem Befehl
Object.freeze()
können Sie ein Objekt „einfrieren“. Sie können einem solchen Objekt keine neuen Eigenschaften hinzufügen. Eigenschaften können weder gelöscht noch ihre Werte geändert werden. Mit diesem Befehl wird ein Objekt unveränderlich oder unveränderlich:
"use strict"; let book = Object.freeze({ title : "Functional-Light JavaScript", author : "Kyle Simpson" }); book.title = "Other title";//: Cannot assign to read only property 'title'
Der Befehl
Object.freeze()
führt das sogenannte "flache Einfrieren" von Objekten durch. Dies bedeutet, dass in einem "eingefrorenen" Objekt verschachtelte Objekte geändert werden können. Um ein Objekt tief einzufrieren, müssen Sie alle seine Eigenschaften rekursiv einfrieren.
Objekte klonen
Um Klone (Kopien) von Objekten zu erstellen, können Sie den Befehl
Object.assign()
:
let book = Object.freeze({ title : "JavaScript Allongé", author : "Reginald Braithwaite" }); let clone = Object.assign({}, book);
Dieser Befehl führt ein flaches Kopieren von Objekten durch, dh er kopiert nur Eigenschaften der obersten Ebene. Verschachtelte Objekte sind für Originalobjekte und ihre Kopien üblich.
Objektliteral
Objektliterale bieten Entwicklern eine einfache und unkomplizierte Möglichkeit, Objekte zu erstellen:
let timer = { fn : null, start : function(callback) { this.fn = callback; }, stop : function() {}, }
Diese Methode zum Erstellen von Objekten hat jedoch Nachteile. Insbesondere sind bei diesem Ansatz alle Eigenschaften des Objekts öffentlich verfügbar, die Methoden des Objekts können neu definiert werden und sie können nicht zum Erstellen neuer Instanzen derselben Objekte verwendet werden:
timer.fn;//null timer.start = function() { console.log("New implementation"); }
Object.create () -Methode
Die beiden oben genannten Probleme können durch die gemeinsame Verwendung der Methoden
Object.create()
und
Object.freeze()
.
Wir wenden diese Technik auf unser vorheriges Beispiel an. Erstellen Sie zunächst einen eingefrorenen Prototyp
timerPrototype
, der alle Methoden enthält, die von verschiedenen Instanzen des Objekts benötigt werden. Erstellen Sie anschließend ein Objekt, das ein Nachfolger von
timerPrototype
:
let timerPrototype = Object.freeze({ start : function() {}, stop : function() {} }); let timer = Object.create(timerPrototype); timer.__proto__ === timerPrototype; //true
Wenn der Prototyp vor Änderungen geschützt ist, kann das Objekt, das sein Erbe ist, die im Prototyp definierten Eigenschaften nicht ändern. Jetzt können die Methoden
start()
und
stop()
nicht überschrieben werden:
"use strict"; timer.start = function() { console.log("New implementation"); }
Mit dem
Object.create(timerPrototype)
können mehrere Objekte mit demselben Prototyp erstellt werden.
Konstruktorfunktion
JavaScript verfügt über sogenannte Konstruktorfunktionen, die "syntaktischer Zucker" sind, um die oben genannten Schritte zum Erstellen neuer Objekte auszuführen. Betrachten Sie
ein Beispiel :
function Timer(callback){ this.fn = callback; } Timer.prototype = { start : function() {}, stop : function() {} } function getTodos() {} let timer = new Timer(getTodos);
Sie können jede Funktion als Konstruktor verwenden. Der Konstruktor wird mit dem
new
Schlüsselwort aufgerufen. Ein Objekt, das mit einer Konstruktorfunktion namens
FunctionConstructor
, erhält einen Prototyp
FunctionConstructor.prototype
:
let timer = new Timer(); timer.__proto__ === Timer.prototype;
Um eine Änderung des Prototyps zu verhindern, können Sie den Prototyp erneut einfrieren:
Timer.prototype = Object.freeze({ start : function() {}, stop : function() {} });
▍ Stichwort neu
Wenn ein Befehl des Formulars
new Timer()
ausgeführt wird, werden dieselben Aktionen ausgeführt wie die Funktion
newTimer()
:
function newTimer(){ let newObj = Object.create(Timer.prototype); let returnObj = Timer.call(newObj, arguments); if(returnObj) return returnObj; return newObj; }
Hier wird ein neues Objekt erstellt, dessen Prototyp
Timer.prototype
. Anschließend wird die
Timer
Funktion aufgerufen, mit der die Felder für das neue Objekt festgelegt werden.
Klassenschlüsselwort
Mit ECMAScript 2015 wurde eine neue Methode zur Durchführung der oben genannten Aktionen eingeführt, bei der es sich um eine weitere Charge „syntaktischen Zuckers“ handelt. Wir sprechen über das
class
und die damit verbundenen zugehörigen Konstrukte. Betrachten Sie
ein Beispiel :
class Timer{ constructor(callback){ this.fn = callback; } start() {} stop() {} } Object.freeze(Timer.prototype);
Ein Objekt, das mit dem Schlüsselwort
class
basierend auf einer Klasse namens
ClassName
, hat den Prototyp
ClassName.prototype
. Verwenden Sie beim Erstellen eines Objekts basierend auf einer Klasse das
new
Schlüsselwort:
let timer= new Timer(); timer.__proto__ === Timer.prototype;
Die Verwendung von Klassen macht Prototypen nicht unveränderlich. Falls erforderlich, müssen sie auf die gleiche Weise „eingefroren“ werden, wie wir es bereits getan haben:
Object.freeze(Timer.prototype);
Prototypbasierte Vererbung
In JavaScript erben Objekte Eigenschaften und Methoden von anderen Objekten. Konstruktorfunktionen und -klassen sind „syntaktischer Zucker“ zum Erstellen von Prototypobjekten, die alle erforderlichen Methoden enthalten. Mit ihnen werden neue Objekte erstellt, die die Erben des Prototyps sind, deren Eigenschaften für eine bestimmte Instanz mithilfe der Konstruktorfunktion oder mithilfe der Klassenmechanismen festgelegt werden.
Es wäre schön, wenn Konstruktorfunktionen und -klassen Prototypen automatisch unveränderlich machen könnten.
Die Stärken der Prototypvererbung sind Speichereinsparungen. Tatsache ist, dass ein Prototyp nur einmal erstellt wird, wonach alle auf seiner Basis erstellten Objekte ihn verwenden.
▍ Das Problem des Fehlens integrierter Verkapselungsmechanismen
Die Prototyp-Vererbungsvorlage verwendet nicht die Trennung der Eigenschaften von Objekten in private und öffentliche. Alle Eigenschaften von Objekten sind öffentlich verfügbar.
Beispielsweise gibt der Befehl
Object.keys()
ein Array zurück, das alle Eigenschaftsschlüssel des Objekts enthält. Es kann verwendet werden, um alle Eigenschaften eines Objekts zu durchlaufen:
function logProperty(name){ console.log(name); // console.log(obj[name]); // } Object.keys(obj).forEach(logProperty);
Es gibt ein Muster, das private Eigenschaften nachahmt und sich auf die Tatsache stützt, dass Entwickler nicht auf Eigenschaften zugreifen, deren Namen mit einem Unterstrich (
_
) beginnen:
class Timer{ constructor(callback){ this._fn = callback; this._timerId = 0; } }
Werksfunktionen
Eingekapselte Objekte in JavaScript können mithilfe von Factory-Funktionen erstellt werden. Es sieht so aus:
function TodoStore(callback){ let fn = callback; function start() {}, function stop() {} return Object.freeze({ start, stop }); }
Hier ist die Variable
fn
privat. Nur die Methoden
start()
und
stop()
sind öffentlich verfügbar. Diese Methoden können nicht extern geändert werden. Das Schlüsselwort this wird hier nicht verwendet. Wenn Sie diese Methode zum Erstellen von Objekten verwenden, ist das Problem des Verlusts
this
Kontexts irrelevant.
Der Befehl
return
verwendet ein Objektliteral, das nur Funktionen enthält. Darüber hinaus werden diese Funktionen zum Abschluss erklärt, sie haben einen gemeinsamen Zustand. Um eine öffentliche API eines Objekts einzufrieren, wird der bereits bekannte Befehl
Object.freeze()
.
Hier haben wir in den Beispielen das
Timer
Objekt verwendet. In
diesem Material finden Sie die vollständige Implementierung.
Zusammenfassung
In JavaScript werden die Werte primitiver Typen, gewöhnlicher Objekte und Funktionen als Objekte behandelt. Objekte sind dynamischer Natur und können als assoziative Arrays verwendet werden. Objekte sind Erben anderer Objekte. Konstruktorfunktionen und -klassen sind „syntaktischer Zucker“, mit dem Sie Objekte basierend auf Prototypen erstellen können. Sie können die
Object.create()
-Methode verwenden, um die Einzelvererbung zu organisieren, und
Object.create()
um die Mehrfachvererbung zu organisieren. Sie können Factory-Funktionen verwenden, um gekapselte Objekte zu erstellen.
Liebe Leser! Wenn Sie aus anderen Sprachen zu JavaScript gekommen sind, teilen Sie uns bitte mit, was Sie an JS-Objekten mögen oder nicht mögen, im Vergleich zur Implementierung von Objekten in Sprachen, die Sie bereits kennen.
