Zum Inhalt springen
aviral gupta

// I2.1 · ca. 33 Min. · Aufbau

Die Prototypenkette

Nach dieser Lektion können Sie sagen, wo JavaScript eine Eigenschaft findet: am Objekt selbst oder weiter oben in seiner Prototypenkette. Mit Object.create bauen Sie Objekte auf einem gemeinsamen Prototyp.

Lektion 1 von 5 in I2 Objekte, Prototypen und Klassen

Anfang des Moduls

Danach können Sie

  • Erklären, wie eine Eigenschaftssuche die Prototypenkette entlangläuft, und die Kette mit Object.getPrototypeOf verfolgen
  • Ein Objekt mit Object.create auf einem gewählten Prototyp aufbauen und mit Object.hasOwn eigene von geerbten Eigenschaften unterscheiden
  • Methoden auf einem Prototyp teilen und eine geerbte Eigenschaft durch eine eigene überdecken
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen, aus Lektion B5.3: Was gibt dieser Code aus?

    const base = {a: 1, b: 2};
    const copy = {...base, b: 3};
    console.log(copy.a, copy.b, base.b);
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. obj hat keine eigenen Schlüssel. Was gibt dieser Code aus?

    const proto = {greet() { return "hello"; }};
    const obj = Object.create(proto);
    console.log(Object.keys(obj).length, obj.greet());
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie die Methode, die ein neues Objekt mit animal als Prototyp erzeugt.

    const animal = {speak() { return "..."; }};
    const cat = Object.____(animal);
    const cat = Object.(animal);
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jeden Begriff und jeden Aufruf seiner Bedeutung zu.

  5. Üben · Aufgabe 5 von 7

    Zwei Objekte teilen sich einen Prototyp, und a setzt color. Was gibt dieser Code aus?

    const proto = {color: "red"};
    const a = Object.create(proto);
    const b = Object.create(proto);
    a.color = "blue";
    console.log(a.color, b.color, proto.color);
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. for...in und Object.keys auf demselben Objekt. Was gibt dieser Code aus?

    const proto = {shared: 1};
    const obj = Object.create(proto);
    obj.own = 2;
    const seen = [];
    for (const key in obj) seen.push(key);
    console.log(seen.join(","), Object.keys(obj).join(","));
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe: Schreiben Sie einen Prototyp accountProto mit zwei Methoden, deposit(amount), die zu this.balance addiert und es zurückgibt, und describe(), die einen Text wie "Ada: 50 EUR" zurückgibt. Schreiben Sie makeAccount(owner), das mit Object.create ein Konto auf accountProto aufbaut. Erzeugen Sie zwei Konten, zahlen Sie auf eines ein und zeigen Sie, dass beide dieselbe deposit-Methode teilen.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Zwei Tiere, ein Prototyp

animal enthält einen Standardlaut und eine Methode speak(). cat und fish werden mit Object.create(animal) erzeugt, beide verweisen also darauf. cat bekommt einen eigenen sound, der den Standard überdeckt; fish behält den geerbten. Das Programm prüft dann die Verweise und die Arten von Eigenschaften und folgt der Kette bis zu ihrem Ende.

main.js

// A prototype with a shared method.
const animal = {
  sound: "...",
  speak() {
    return `${this.name} says ${this.sound}`;
  }
};

// Two objects that link to it.
const cat = Object.create(animal);
cat.name = "Mia";
cat.sound = "meow"; // an own property: it shadows animal.sound
const fish = Object.create(animal);
fish.name = "Bubbles";

console.log(cat.speak());
console.log(fish.speak());
console.log(Object.getPrototypeOf(cat) === animal);
console.log(Object.hasOwn(cat, "sound"), Object.hasOwn(fish, "sound"));
console.log("speak" in fish, Object.hasOwn(fish, "speak"));
console.log(cat.speak === fish.speak);
console.log(Object.keys(cat));

// The chain goes on: animal links to Object.prototype, which links to null.
console.log(Object.getPrototypeOf(animal) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype));

Ausführen mit

node main.js

Ausgabe

Mia says meow
Bubbles says ...
true
true false
true false
true
[ 'name', 'sound' ]
true
null
  • speak() existiert nur einmal, an animal, aber this ist cat oder fish, je nachdem, worauf es aufgerufen wurde.
  • fish hat keinen eigenen sound, die Suche fand also das "..." von animal.
  • "speak" in fish ist true, Object.hasOwn(fish, "speak") ist false: speak ist geerbt.
  • Object.keys(cat) listet nur die eigenen Eigenschaften von cat.
  • Die Kette endet bei null, dem Prototyp von Object.prototype.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Eigen, geerbt oder fehlend

Schreiben Sie describe(obj, key). Die Funktion gibt "own" zurück, wenn key eine eigene Eigenschaft von obj ist, "inherited", wenn obj key nur über seine Prototypenkette bekommt, und "missing", wenn der Schlüssel gar nicht gefunden wird. Der Starter verwendet nur den Operator in und nennt deshalb geerbte Eigenschaften eigene.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: Geerbte Schlüssel kommen als eigene zurück. Welche Prüfung ist nur für das Objekt selbst wahr?

  2. Hinweis 2

    Object.hasOwn(obj, key) ist nur für eigene Eigenschaften true; key in obj ist für eigene und geerbte true.

  3. Hinweis 3

    Prüfen Sie zuerst Object.hasOwn und geben Sie "own" zurück, dann key in obj und geben Sie "inherited" zurück, sonst "missing".

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function describe(obj, key) {
  if (Object.hasOwn(obj, key)) return "own";
  if (key in obj) return "inherited";
  return "missing";
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export function describe(obj, key) {
  if (key in obj) return "own";
  return "missing";
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {describe} from './main.js';

test('Eine Eigenschaft am Objekt selbst ist eigen', () => {
  const got = describe({name: 'Ada'}, 'name');
  assert.equal(got, 'own', `describe({name}, 'name') ergab ${got}`);
});

test('Eine Eigenschaft vom Prototyp ist geerbt', () => {
  const child = Object.create({kind: 'fruit'});
  const got = describe(child, 'kind');
  assert.equal(got, 'inherited', `describe(child, 'kind') ergab ${got}`);
});

test('toString an einem einfachen Objekt ist geerbt', () => {
  const got = describe({}, 'toString');
  assert.equal(got, 'inherited', `describe({}, 'toString') ergab ${got}`);
});

test('Ein unbekannter Schlüssel fehlt', () => {
  const got = describe({}, 'colour');
  assert.equal(got, 'missing', `describe({}, 'colour') ergab ${got}`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Übung 2 von 2

Zähler, die sich eine Methode teilen

makeCounter(start) soll einen Zähler zurückgeben, dessen increment() seinen count um eins erhöht und ihn zurückgibt. Die Methode soll nur einmal auf counterProto liegen und nicht an jedem Zähler. Der Starter gibt jedem Zähler eine eigene Kopie von increment. Bauen Sie den Zähler mit Object.create(counterProto) und geben Sie ihm nur einen eigenen count.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: increment funktioniert, ist aber eine eigene Eigenschaft jedes Zählers. Wo sollte es stattdessen liegen?

  2. Hinweis 2

    Object.create(counterProto) liefert ein leeres Objekt, das increment erbt.

  3. Hinweis 3

    const counter = Object.create(counterProto); counter.count = start; return counter;

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export const counterProto = {
  increment() {
    this.count += 1;
    return this.count;
  }
};

export function makeCounter(start) {
  const counter = Object.create(counterProto);
  counter.count = start;
  return counter;
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

export const counterProto = {
  increment() {
    this.count += 1;
    return this.count;
  }
};

export function makeCounter(start) {
  return {
    count: start,
    increment() {
      this.count += 1;
      return this.count;
    }
  };
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {counterProto, makeCounter} from './main.js';

test('increment erhöht um eins und gibt den neuen count zurück', () => {
  const counter = makeCounter(5);
  counter.increment();
  const got = counter.increment();
  assert.equal(got, 7, `zwei Aufrufe von increment ab 5 ergaben ${got}`);
});

test('Der Prototyp eines Zählers ist counterProto', () => {
  const counter = makeCounter(0);
  assert.equal(Object.getPrototypeOf(counter) === counterProto, true, 'Object.getPrototypeOf(counter) sollte counterProto sein');
});

test('increment ist geerbt, keine eigene Eigenschaft', () => {
  const counter = makeCounter(0);
  assert.equal(Object.hasOwn(counter, 'increment'), false, 'jeder Zähler hat sein eigenes increment; es sollte von counterProto kommen');
});

test('Zwei Zähler behalten ihren eigenen count', () => {
  const a = makeCounter(0);
  const b = makeCounter(10);
  a.increment();
  assert.deepEqual([a.count, b.count], [1, 10], `die Zählerstände sind ${a.count} und ${b.count}`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Object.create ohne Prototyp aufrufen

const animal = {speak() { return "..."; }};
const cat = Object.create();
console.log(cat.speak());

Was Node.js ausgibt

TypeError: Object prototype may only be an Object or null: undefined

Warum, und die Lösung

Object.create braucht als erstes Argument das Objekt, auf das verwiesen werden soll; es kopiert keines und rät auch keines. Übergeben Sie den Prototyp: Object.create(animal). Wollen Sie wirklich ein Objekt ganz ohne Prototyp, sagen Sie es ausdrücklich mit Object.create(null).

hasOwnProperty an einem Objekt ohne Prototyp aufrufen

const stock = Object.create(null);
stock.apples = 3;
console.log(stock.hasOwnProperty("apples"));

Was Node.js ausgibt

TypeError: stock.hasOwnProperty is not a function

Warum, und die Lösung

hasOwnProperty wird von Object.prototype geerbt. Ein mit Object.create(null) erzeugtes Objekt hat keinen Prototyp, also auch kein hasOwnProperty. Verwenden Sie stattdessen die statische Methode, die für jedes Objekt funktioniert: Object.hasOwn(stock, "apples").

Eine Pfeilfunktion als geteilte Methode

const proto = {
  hello: () => `I am ${this.name}`
};
const a = Object.create(proto);
a.name = "Ada";
console.log(a.hello());

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'name')

Warum, und die Lösung

Eine Pfeilfunktion hat kein eigenes this; sie übernimmt this vom umgebenden Code. Am Anfang eines Moduls ist das undefined, this.name scheitert also, egal welches Objekt hello aufgerufen hat. Schreiben Sie geteilte Methoden mit der Methodensyntax, hello() { return `I am ${this.name}`; }, damit this das Objekt vor dem Punkt ist.

JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Ein Objekt verweist auf seinen Prototyp

Jedes Objekt hat einen verborgenen Verweis auf ein anderes Objekt, seinen Prototyp. Lesen Sie obj.x, sucht JavaScript x zuerst an obj. Hat obj kein x, sucht es am Prototyp von obj, dann am Prototyp dieses Objekts und so weiter. Das erste x, das es findet, gewinnt. Am Ende der Kette steht null; wurde x bis dahin nicht gefunden, ist das Ergebnis undefined. Object.getPrototypeOf(obj) liefert Ihnen das nächste Kettenglied. Ein einfaches Objekt {} verweist auf Object.prototype, deshalb hat jedes Objekt toString.

Eigene und geerbte Eigenschaften

Object.create(proto) erzeugt ein neues, leeres Objekt, dessen Prototyp proto ist. Es wird nichts kopiert: Eine Eigenschaft, die später zu proto hinzukommt, ist auch über das neue Objekt sichtbar. Eine Eigenschaft, die am Objekt selbst liegt, ist eine eigene Eigenschaft; eine weiter oben gefundene ist geerbt. Object.hasOwn(obj, key) ist nur für eigene Eigenschaften true, key in obj dagegen für beide. Object.keys, JSON.stringify und Spread zeigen nur eigene Eigenschaften. Object.create(null) erzeugt ein Objekt ganz ohne Prototyp, es hat also weder toString noch hasOwnProperty.

Geteilte Methoden und Überdeckung

Legen Sie eine Methode auf den Prototyp, kann jedes Objekt, das darauf verweist, sie aufrufen, und die Funktion existiert trotzdem nur einmal. In der Methode ist this das Objekt, auf dem sie aufgerufen wurde, nicht der Prototyp; ein einziges speak() kann also für jedes Tier einen anderen Namen ausgeben. obj.x = value erzeugt oder ändert immer eine eigene Eigenschaft an obj; den Prototyp ändert es nie. Diese eigene Eigenschaft verbirgt, man sagt überdeckt, die geerbte, aber nur für dieses Objekt. delete obj.x entfernt die eigene Eigenschaft, und der geerbte Wert wird wieder sichtbar.

Quellen

Zuletzt geprüft am 5. Oktober 2026