Klassen und Module in JavaScript mit Entwicklerwerkzeugen

Lerne, wie professionelle JavaScript-Projekte organisiert sind. Erstelle Objekte mit Klassen, privaten Feldern und Vererbung und lerne die Prototypenkette kennen, auf der Klassen aufbauen. Teile Code in ES-Module auf, die im Browser und in Node.js laufen, verwalte Pakete mit npm und package.json und nutze die alltäglichen Werkzeuge eines modernen Arbeitsablaufs: einen Linter und Codeformatierer, einen Entwicklungsserver und Bundler sowie einen Testrunner. Zum Abschluss siehst du, wo TypeScript und Frontend-Frameworks in diese Werkzeugkette passen.

AnfängerEinheit 9 von 9 in Kurs: JavaScript – DOM, Ereignisse und asynchroner Code

Was du lernst

  1. Erstelle mit Klassen Objekte mit gemeinsamem Verhalten, schütze ihre Daten, baue Hierarchien durch Vererbung auf und erkläre die Prototypenkette, auf der Klassen aufbauen.
    • Definiere eine Klasse und erstelle Objekte mit new
      Schreibe eine Klasse mit Konstruktor, Feldern, Methoden, Gettern und Settern, erstelle Instanzen mit new und sorge dafür, dass this auf das richtige Objekt verweist.
    • Schütze Daten mit privaten Mitgliedern und nutze Werte mit statischen Mitgliedern gemeinsam
      Verbirg den internen Zustand eines Objekts hinter privaten Feldern und Methoden und lege Werte und Hilfsfunktionen, die zur Klasse als Ganzes gehören, in statischen Mitgliedern ab.
    • Baue Klassenhierarchien mit extends und super auf
      Erstelle Unterklassen, die Verhalten erben und überschreiben, rufe die Oberklasse mit super auf, prüfe Typen mit instanceof und entscheide, wann Vererbung oder Komposition besser passt.
    • Erkläre die Prototypen hinter Objekten und Klassen
      Beschreibe, wie JavaScript Eigenschaften entlang der Prototypenkette findet, wie Klassen und extends diese Kette aufbauen und warum eingebaute Prototypen unverändert bleiben.
  2. Teile ein Programm in Module auf, die Funktionen exportieren und importieren, führe sie in Browsern und Node.js aus, lade Code bei Bedarf und gib jedem Modul eine klare Aufgabe.
    • Exportiere und importiere Code zwischen Dateien
      Teile ein Programm in ES-Module auf und verbinde sie durch benannte und Standardexporte, umbenannte Importe und Namensraumimporte sowie Reexporte. Verstehe dabei, wie sich Modulgültigkeitsbereich und Live-Bindungen verhalten.
    • Führe Module im Browser und in Node.js aus
      Lade Module auf einer Webseite mit type="module" von einem lokalen Server, löse Modulpfade und bloße Namen auf und verstehe, wie Node.js zwischen ES-Modulen und CommonJS wählt.
    • Lade Module bei Bedarf und gliedere ein Projekt in Module
      Nutze dynamisches import() und Top-Level-await, teile eine Anwendung in Module mit klaren Aufgaben auf und vermeide Probleme mit Seiteneffekten und zyklischen Importen.
  3. Beschreibe ein Projekt in package.json, führe seine Aufgaben mit npm-Skripten aus und installiere, aktualisiere und wähle Abhängigkeiten so aus, dass jeder Computer dieselbe funktionierende Zusammenstellung von Paketen erhält.
    • Richte ein Projekt mit npm und package.json ein
      Erstelle ein Projekt mit npm init, lies und bearbeite die wichtigsten Felder von package.json, führe Aufgaben mit npm-Skripten und npx aus und lies semantische Versionsnummern.
    • Installiere, aktualisiere und wähle Abhängigkeiten aus
      Installiere Pakete als Laufzeit- oder Entwicklungsabhängigkeiten, lies Versionsbereiche, nutze package-lock.json und npm ci für reproduzierbare Installationen, halte Abhängigkeiten aktuell und wähle Pakete sicher aus.
  4. Nutze einen Linter und einen Codeformatierer, um Probleme zu erkennen und einen einheitlichen Stil beizubehalten, einen Entwicklungsserver und Bundler, um ein Projekt auszuführen und auszuliefern, und einen Testrunner, um die Funktionsfähigkeit des Codes zu prüfen.
    • Erkenne Probleme mit einem Linter und formatiere Code automatisch
      Nutze ESLint, um wahrscheinliche Fehler zu finden, ohne den Code auszuführen, und Prettier für ein einheitliches Layout. Konfiguriere beide und führe sie über Skripte und den Editor aus.
    • Stelle ein Projekt mit einem Entwicklungsserver bereit und bündele es mit einem Bundler
      Erkläre, was Bundler und Entwicklungsserver tun, durchlaufe den Zyklus aus Entwickeln, Bauen und Vorschau mit Vite und verstehe Tree Shaking, Minifizierung, Dateinamen mit Hash, Source Maps und Umgebungsvariablen.
    • Prüfe Code automatisch mit einem Testrunner
      Schreibe Unittests mit Assertions für Funktionen und Klassen, führe sie mit dem eingebauten Node.js-Testrunner oder Vitest aus, lies Fehlermeldungen und entwirf Code, der sich leicht testen lässt.
  5. Erkläre, was TypeScript und Frontend-Frameworks zu JavaScript hinzufügen, wie sie Module, npm und Buildwerkzeuge nutzen und wie alle Werkzeuge in einem Projekt zusammenarbeiten.
    • Erkläre, was TypeScript zu JavaScript hinzufügt
      Beschreibe, wie statische Typen in TypeScript Fehler vor der Ausführung erkennen, wie TypeScript-Code zu JavaScript wird und wann sich der zusätzliche Schritt lohnt.
    • Ordne Frameworks in eine vollständige moderne Werkzeugkette ein
      Erkläre, was Frontend-Frameworks tun und wie sie auf Modulen, npm und Bundlern aufbauen, und füge die Werkzeuge dieser Einheit zu einem alltäglichen Arbeitsablauf zusammen.

Klassen und Module in JavaScript einfach erklärt

5 Kapitel

1

Erstelle Objekte mit gemeinsamem Verhalten

Ein einfaches Objekt gruppiert zusammengehörige Werte. Eine Klasse ergänzt eine wiederholbare Möglichkeit, Objekte mit eigenen Daten und gemeinsamem Verhalten zu erstellen. Beginne mit Konstruktoren und Methoden und steuere dann Änderungen über private Felder und eine öffentliche Schnittstelle. Vererbung ermöglicht verwandten Klassen, dieses Verhalten zu spezialisieren. Die Prototypenkette erklärt, wie JavaScript die Methoden findet und warum eine Instanz andernorts gespeicherten Code nutzen kann.

1.1 Erstelle und nutze Klasseninstanzen

Eine Klasse beschreibt Objekte mit derselben Struktur und demselben Verhalten. Jedes daraus erstellte Objekt ist eine Instanz. Verwende eine Klasse, wenn mehrere Objekte dieselben Operationen benötigen; für einen einzelnen Einstellungswert reicht oft ein einfaches Objekt.

Gib jedem Objekt eigene Daten

Klassennamen verwenden üblicherweise PascalCase, etwa Rectangle. Der constructor läuft jedes Mal, wenn new eine Instanz erstellt. Darin verweist this auf das neue Objekt. Eine Zuweisung an this.width speichert eine Instanzeigenschaft; ein Parameter namens width allein ist nur eine lokale Variable.

class Rectangle {
  constructor(width, height) {
    this.width = width; // cm
    this.height = height;
  }
  area() {
    return this.width * this.height;
  }
  perimeter() {
    return 2 * (this.width + this.height);
  }
}
const a = new Rectangle(3, 4);
const b = new Rectangle(5, 2);
a.area();      // 12
a.perimeter(); // 14
b.area();      // 10

Bei a.area() ruft JavaScript die Methode auf und setzt this auf a. Die Breite von 3 cm multipliziert mit der Höhe von 4 cm ergibt 12 cm². Für den Umfang werden die beiden unterschiedlichen Seiten addiert und diese Summe verdoppelt. Das ergibt 14 cm. Eine Änderung von b.width ändert nur b.

Methoden haben kein Schlüsselwort function und keine Kommas zwischen sich. Eine Klasse hat höchstens einen Konstruktor. Wird er bei einer Klasse ohne extends weggelassen, erhält die Klasse einen leeren Standardkonstruktor. new gibt die erstellte Instanz automatisch zurück.

Ein Feld deklariert eine Eigenschaft im Klassenrumpf: unit = "cm"; gibt jeder Instanz einen eigenen Wert. label; hat zunächst den Wert undefined. In einer Klasse ohne extends werden Instanzfelder initialisiert, bevor der Konstruktorrumpf ausgeführt wird.

Über Zugriffsmethoden lesen und zuweisen

Ein Getter wird ausgeführt, wenn eine Eigenschaft gelesen wird. Mit get area() { return this.width * this.height; } liest du a.area ohne Klammern. Das ist eine Alternative zur obigen Methode, die a.area() verwendet.

Ein Setter wird bei einer Zuweisung ausgeführt und kann ungültige Eingaben ablehnen. Er benötigt einen separaten Speicherplatz: set width(value) { this.width = value; } ruft sich wiederholt selbst auf, bis der Stapel überläuft. Speichere den Wert unter einem anderen Namen, etwa im privaten Feld #width.

Das Empfängerobjekt beim Übergeben einer Methode beibehalten
class Counter {
  count = 0;
  increment() { this.count++; }
}
const counter = new Counter();
const inc = counter.increment;
// inc(); // TypeError: this is undefined
const safeInc = () => counter.increment();
safeInc(); // counter.count is 1

Klassenmethoden laufen im strikten Modus. Ein losgelöster Aufruf hat kein Empfängerobjekt vor dem Punkt, daher ist this gleich undefined. Auch der Aufrufer eines Callbacks kann ein anderes Empfängerobjekt übergeben. Ein Pfeilfunktions-Wrapper erhält den Aufruf auf counter; counter.increment.bind(counter) erstellt eine gebundene Funktion. Ein Pfeilfunktionsfeld, increment = () => { this.count++; };, erfasst ebenfalls das this der Instanz.

Der Aufruf von Rectangle(3, 4) ohne new löst einen TypeError aus. Die Verwendung einer Klasse vor der Initialisierung ihrer Deklaration löst einen ReferenceError aus. Klassen unterscheiden sich hier von Funktionsdeklarationen, die früher in einer Datei aufgerufen werden können.

JSON erhält Daten, nicht das Verhalten von Klassen. JSON.stringify(a) speichert die eigenen öffentlichen Werte für Breite und Höhe. Das Parsen dieses Textes erstellt ein einfaches Objekt; erstelle mit new Rectangle(data.width, data.height) wieder eine Instanz, um ihre Methoden zu nutzen.

Wichtige Erkenntnisse

  • new erstellt eine Instanz und führt ihren Konstruktor aus; this bezeichnet das Empfängerobjekt eines Methodenaufrufs.
  • Felder enthalten die Daten jeder Instanz; gewöhnliche Methoden werden gemeinsam genutzt.
  • Getter werden wie Eigenschaften gelesen; Setter laufen bei einer Zuweisung und benötigen separaten Speicher.
  • Verwende einen Pfeilfunktions-Wrapper oder eine gebundene Funktion, wenn ein Callback sein Empfängerobjekt behalten muss.
  • JSON stellt beim Parsen gespeicherter Daten keine Klassenmethoden wieder her.

1.2 Schütze den Zustand mit privaten Feldern

Ein Objekt kann eine kleine öffentliche Schnittstelle anbieten und gleichzeitig seine gespeicherten Daten privat halten. Das ist Kapselung. Die Schnittstelle entscheidet, welche Änderungen gültig sind; der private Zugriffsschutz allein prüft keinen Wert, der an einen öffentlichen Setter übergeben wird.

Validierung an der Schnittstelle platzieren

Ein privates Feld beginnt mit # und muss im Klassenrumpf deklariert werden. Code innerhalb dieser Klasse liest es über this.#target. Code außerhalb kann t.#target weder lesen noch schreiben: Das ist ein Syntaxfehler und kein Eigenschaftszugriff, der undefined zurückgibt.

class Thermostat {
  static MIN = 10;
  static MAX = 30;
  #target = 20;

  get target() { return this.#target; }
  set target(value) {
    if (!Number.isFinite(value) ||
        value < Thermostat.MIN ||
        value > Thermostat.MAX) {
      throw new RangeError("Target must be between 10 and 30 °C");
    }
    this.#target = value;
  }
}
const t = new Thermostat();
t.target = 22;
t.target; // 22
// t.target = 35; // throws RangeError

Der Getter ermöglicht das Lesen des Werts, ohne den Speicher offenzulegen. Der Setter lehnt zuerst nicht endliche oder nicht numerische Eingaben ab, dann Werte außerhalb des Bereichs von 10 bis einschließlich 30 °C. Nur ein akzeptierter Wert erreicht die Zuweisung. Nach einem abgelehnten Versuch, 35 °C einzustellen, bleibt der Sollwert bei 22 °C. Auch eine numerische Zeichenkette wie "22" besteht die Prüfung mit Number.isFinite nicht.

Getter und Setter verwenden #target, sodass die Zuweisung an t.target den Setter nicht rekursiv aufruft. Die Namen target und #target sind verschieden. Ein vorangestellter Unterstrich wie in _target bittet andere Programmierer nur darum, eine öffentliche Eigenschaft als intern zu behandeln; JavaScript erlaubt weiterhin den Zugriff darauf.

Private Felder erscheinen nicht in Object.keys, for...in oder bei der JSON-Serialisierung. Dieses Thermostat hat keine eigenen öffentlichen Felder, daher ergibt JSON.stringify(t) den Wert "{}". Zum Speichern eines Objekts kann deshalb eine ausdrückliche öffentliche Methode nötig sein, die die zu speichernden Daten zurückgibt.

Interne Hilfsmethoden privat halten

Eine Methode wie #check(value) { ... } kann Validierungsschritte enthalten und wird innerhalb der Klasse als this.#check(value) aufgerufen. Sie ist nicht Teil der öffentlichen Schnittstelle. Innerhalb der Klasse prüft #target in obj, ob ein Objekt dieses private Feld besitzt.

Eine Unterklasse kann den privaten Namen ihrer Oberklasse nicht direkt verwenden. Sie kann den öffentlichen Getter oder Setter der Oberklasse verwenden, der in der Klasse ausgeführt wird, die das Feld deklariert hat. So behält die Oberklasse die Kontrolle über ihren eigenen Zustand.

Gemeinsam genutzte Aufgaben auf der Klasse ablegen

Ein statisches Mitglied gehört zur Klasse. Thermostat.MIN ist 10, während t.MIN den Wert undefined hat. Diese statischen Schranken sind öffentliche Felder; static allein macht sie nicht schreibgeschützt.

class Tracked {
  static count = 0;
  constructor() { Tracked.count++; }
}
new Tracked();
new Tracked();
new Tracked();
Tracked.count; // 3

Jeder Konstruktor erhöht einen Zähler auf Klassenebene. Ein Instanzfeld würde dagegen jedem Objekt einen eigenen Zähler geben. Eine statische Fabrikmethode wie static square(side) { return new Rectangle(side, side); } gehört in Rectangle und wird als Rectangle.square(5) aufgerufen. Eine statische Vergleichshilfsfunktion kann an sort übergeben werden, wenn sie die verglichenen Objekte als Argumente entgegennimmt.

Innerhalb einer statischen Methode ist this die Klasse, auf der sie aufgerufen wurde; es ist keine Rechteckinstanz mit einer Breite. Ein Initialisierungsblock static { ... } führt die Einrichtung einmal aus, wenn die Klasse definiert wird, und kann auf die privaten Mitglieder dieser Klasse zugreifen.

Wichtige Erkenntnisse

  • Private #-Felder werden von JavaScript geschützt; ein Unterstrich ist nur eine Konvention.
  • Validiere über die öffentliche Schnittstelle, bevor du privaten Zustand änderst.
  • Private Felder fehlen bei der gewöhnlichen Aufzählung von Schlüsseln und bei der JSON-Serialisierung.
  • Unterklassen nutzen die öffentliche Schnittstelle der Oberklasse, um mit deren privatem Zustand zu arbeiten.
  • Rufe statische Mitglieder auf der Klasse auf; sie enthalten nicht die Daten der einzelnen Instanzen.
  • Ein statischer Initialisierungsblock wird einmal ausgeführt, wenn seine Klasse definiert wird.

1.3 Spezialisiere eine Klasse durch Vererbung

Vererbung bildet eine „ist ein“-Beziehung ab. Ein Kreis ist eine Form, daher kann eine Klasse Circle die gemeinsame Beschreibung einer Form erben und zugleich eine eigene Flächenberechnung bereitstellen. Eine Unterklasse erbt Verhalten, ohne jede Methode in ihren Rumpf zu kopieren.

Initialisiere zuerst die Oberklasse

class Circle extends Shape macht Circle zu einer Unterklasse und Shape zu ihrer Oberklasse. In einem Unterklassenkonstruktor ruft super(...) den Konstruktor der Oberklasse auf. Dieser Aufruf muss vor der ersten Verwendung von this ausgeführt werden. Eine Unterklasse ohne Konstruktor erhält einen, der ihre Argumente an die Oberklasse weitergibt.

class Shape {
  constructor(name) { this.name = name; }
  area() { return 0; }
  describe() {
    return this.name + " with area " +
      this.area().toFixed(2) + " cm²";
  }
}
class Circle extends Shape {
  constructor(radius) {
    super("Circle");
    this.radius = radius;
  }
  area() { return Math.PI * this.radius ** 2; }
}
class Rectangle extends Shape {
  constructor(width, height) {
    super("Rectangle");
    this.width = width;
    this.height = height;
  }
  area() { return this.width * this.height; }
}

Der Aufruf new Circle(2).describe() ergibt "Circle with area 12.57 cm²". Zuerst setzt super den Namen. Der Kreis speichert seinen Radius. Das geerbte describe() ruft dann this.area() auf, wodurch die Methode des Kreises gefunden wird. toFixed(2) formatiert das Ergebnis für die Anzeige. new Rectangle(3, 4).describe() ergibt "Rectangle with area 12.00 cm²".

Überschreibe oder erweitere eine Methode

Eine Unterklasse überschreibt eine Methode, indem sie eine Methode mit demselben Namen deklariert. Sie kann die Version der Oberklasse über super.methodName() aufrufen.

class Square extends Rectangle {
  constructor(side) {
    super(side, side);
    this.name = "Square";
  }
  describe() {
    return super.describe() +
      " (all sides " + this.width + " cm)";
  }
}
new Square(5).describe();
// "Square with area 25.00 cm² (all sides 5 cm)"

super(side, side) initialisiert Breite und Höhe mit demselben Wert. Die geerbte Flächenmethode multipliziert sie, und die überschreibende Methode ergänzt die geerbte Beschreibung um Informationen. Werden erforderliche Argumente für die Oberklasse vergessen, können ihre Eigenschaften den Wert undefined haben; der Aufruf von super() allein reicht nicht, wenn die Oberklasse Werte benötigt.

Polymorphie bedeutet, dass derselbe Aufruf unterschiedliches Verhalten auswählen kann. Eine Schleife kann s.describe() auf Kreisen und Rechtecken aufrufen; jede Beschreibung ruft das passende area() auf. Das Hinzufügen einer Form mit eigener Flächenmethode erfordert keinen neuen Fall in dieser Schleife.

Sowohl new Circle(2) instanceof Circle als auch new Circle(2) instanceof Shape sind wahr. Auch statische Mitglieder werden geerbt. Die Beziehung einer Instanz zu einer Klasse folgt ihrer Prototypenkette; genau diese prüft instanceof normalerweise.

Wähle eine sinnvolle Beziehung

Eine Klasse kann nur eine Oberklasse erweitern. Für eine „hat ein“-Beziehung verwende Komposition: Ein Auto hat einen Motor und fordert ihn mit this.engine.start() auf, Arbeit zu leisten. Die gemeinsame Nutzung einer Hilfsmethode allein ist kein Grund zu behaupten, dass eine nicht verwandte Klasse eine Art der anderen ist. Ein Mixin kopiert eine Gruppe von Methoden auf einen Prototyp, zum Beispiel mit Object.assign(Rectangle.prototype, serializable). Tiefe Ketten von Oberklassen können es erschweren, Änderungen nachzuvollziehen.

Auch eingebaute Klassen können erweitert werden. Ein Konstruktor von ValidationError extends Error ruft super(message) auf, setzt this.name = "ValidationError" und kann this.field = field speichern. Ein catch-Block kann mit err instanceof ValidationError diesen Fehler anders behandeln und die geerbte Meldung lesen.

Wichtige Erkenntnisse

  • Verwende extends für eine „ist ein“-Beziehung und Komposition für eine „hat ein“-Beziehung.
  • Rufe super(...) mit den benötigten Argumenten für die Oberklasse auf, bevor du this verwendest.
  • Eine überschreibende Methode kann das Verhalten der Oberklasse mit super.methodName() wiederverwenden.
  • Polymorphie ermöglicht, dass ein Methodenaufruf bei verwandten Klassen funktioniert.

1.4 Verfolge die Eigenschaftssuche über Prototypen

Ein Objekt hat eine verborgene Verknüpfung zu einem anderen Objekt, seinem Prototyp, oder zu null. Beim Lesen einer fehlenden Eigenschaft wird dieser Verknüpfung gefolgt. JavaScript sucht weiter, bis es die Eigenschaft findet oder null erreicht; eine erfolglose Suche gibt undefined zurück.

Unterscheide gespeicherte und geerbte Werte
const defaults = { theme: "light", fontSize: 16 };
const settings = Object.create(defaults);
settings.fontSize = 18;
settings.theme;                   // "light"
settings.fontSize;                // 18
defaults.fontSize;                // 16
Object.hasOwn(settings, "theme"); // false
"theme" in settings;              // true
Object.keys(settings);            // ["fontSize"]

Object.create(defaults) erstellt ein leeres Objekt, dessen Prototyp defaults ist. Die Zuweisung an fontSize erstellt eine eigene Eigenschaft, die den geerbten Wert verdeckt. Sie lässt defaults.fontSize unverändert. Nach delete settings.fontSize erreicht die Suche wieder den geerbten Wert 16.

PrüfungBerücksichtigte Eigenschaften
Object.hasOwn(obj, key)Eigene Eigenschaften, ob aufzählbar oder nicht
Object.keys(obj)Eigene aufzählbare Zeichenkettenschlüssel
key in objEigene und geerbte Eigenschaften, ob aufzählbar oder nicht
for...inAufzählbare Zeichenkettenschlüssel, einschließlich geerbter Schlüssel

Eine fehlende eigene Eigenschaft kann dennoch in der Kette existieren. Klassenmethoden sind nicht aufzählbar, daher führt for...in sie normalerweise nicht auf. Lies den Prototyp des Objekts mit Object.getPrototypeOf(settings). Bevorzuge diese Object-Methoden gegenüber dem älteren Zugriff über __proto__.

Sieh, wie Klassen Methoden gemeinsam nutzen

Für eine Rechteckinstanz r ist Object.getPrototypeOf(r) === Rectangle.prototype wahr. Ihre Breite ist eine eigene Eigenschaft, während area normalerweise auf Rectangle.prototype gespeichert ist. Object.hasOwn(r, "area") ist falsch, obwohl r.area() funktioniert. Ein Pfeilfunktionsfeld verhält sich anders: Es erstellt auf jeder Instanz eine eigene Funktionseigenschaft.

Eine geerbte Methode erhält weiterhin das Objekt vor dem Punkt als this. Die gemeinsam genutzte Flächenmethode kann daher für jedes Rechteck andere Maße lesen, ohne auf jedem Objekt eine separate Methode zu speichern.

Für die Formenhierarchie folgt die Suche diesem Weg:

circle -> Circle.prototype -> Shape.prototype
       -> Object.prototype -> null

Die Flächenmethode des Kreises wird zuerst gefunden. Seine Beschreibung stammt von Shape.prototype, und toString kann von Object.prototype stammen. Shape.prototype in der Kette erklärt auch, warum circle instanceof Shape wahr ist.

Der Name Rectangle.prototype bezeichnet den Prototyp, den Rechteckinstanzen erhalten. Er bezeichnet nicht den verborgenen Prototyp der Funktion Rectangle selbst; für diese Klasse ist das Shape, wenn sie Shape erweitert, oder Function.prototype bei einer Klasse ohne Oberklasse.

Erkenne älteren Konstruktorcode
function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.area = function () {
  return this.width * this.height;
};

Konstruktorfunktionen verwenden dieselbe grundlegende Struktur von Instanz und Prototyp. Die Klassensyntax ergänzt Regeln: new ist erforderlich, der Rumpf läuft im strikten Modus, Methoden sind nicht aufzählbar und private Mitglieder sind verfügbar. typeof Rectangle ist bei beiden Formen "function".

Arrays finden map auf Array.prototype; Zeichenkettenmethoden stammen von String.prototype. Vermeide es, eingebaute Prototypen um eigene Methoden zu ergänzen: Bibliotheken und künftige Standards können dieselben Namen mit anderem Verhalten verwenden. Weil eine Bibliothek bereits flatten verwendete, erhielt die Standard-Arraymethode unter anderem deshalb den Namen flat.

Eine gewöhnliche Zuweisung an eine Dateneigenschaft erstellt oder ändert eine eigene Eigenschaft, aber ein geerbter Setter kann die Zuweisung abfangen. Den Prototyp eines vorhandenen Objekts mit Object.setPrototypeOf zu ändern, ist erlaubt, kann aber die Leistung beeinträchtigen; wähle den Prototyp beim Erstellen des Objekts.

Wichtige Erkenntnisse

  • Beim Lesen einer Eigenschaft werden das Objekt, seine Prototypen und schließlich null durchsucht.
  • Eine eigene Eigenschaft kann einen geerbten Wert verdecken, ohne den Prototyp zu ändern.
  • Ob eine Eigenschaft dem Objekt selbst gehört und ob sie aufzählbar ist, sind verschiedene Fragen.
  • Gewöhnliche Klassenmethoden liegen auf dem Prototyp der Instanz und stellen gemeinsam genutztes Verhalten bereit.
  • Eine geerbte Methode verwendet die empfangende Instanz als this.
  • Konstruktorfunktionen und Klassen bauen auf demselben Prototypenmechanismus auf.
  • Lass eingebaute Prototypen unverändert, um Konflikte bei Namen und Verhalten zu vermeiden.
2

Verbinde Dateien mit ES-Modulen

Module ermöglichen es, ein Programm über ein einzelnes Skript hinaus zu erweitern und dabei jede Datei verständlich zu halten. Exporte beschreiben, was eine Datei anbietet, und Importe zeigen, was sie benötigt. Lerne, wie diese Verbindung funktioniert, wie Browser und Node.js Module laden und wie du eine Funktion erst bei Bedarf lädst. Klare Abgrenzungen zwischen Daten, Speicherung und Seitenaktualisierungen machen Code zudem leichter testbar und helfen, zyklische Abhängigkeiten zu vermeiden.

2.1 Exportiere Funktionen und Werte und importiere ihre Bindungen

Ein ES-Modul hat einen eigenen Gültigkeitsbereich. Seine Deklarationen auf oberster Ebene bleiben innerhalb der Datei, sofern sie nicht exportiert werden. Importeure fordern bestimmte Funktionen und Werte an und machen so Abhängigkeiten sichtbar, ohne alles in globalen Variablen abzulegen.

Wähle die passende Exportform
// geometry.js
export const round2 = (n) => Math.round(n * 100) / 100;
export function circleArea(r) {
  return Math.PI * r * r;
}

// shapes.js
import { circleArea, round2 } from "./geometry.js";
export default class Circle {
  constructor(r) { this.r = r; }
  area() { return round2(circleArea(this.r)); }
}

// main.js
import Circle from "./shapes.js";
console.log(new Circle(3).area()); // 28.27

Das Einstiegsmodul importiert eine Klasse. Das Modul der Klasse importiert zwei Hilfsfunktionen. Bei einem Radius von 3 cm beträgt die Fläche etwa 28,274 cm²; die Rundungshilfsfunktion ergibt 28,27. Das Einstiegsmodul erhält nicht automatisch Zugriff auf die Hilfsfunktionen, die innerhalb eines anderen Moduls verwendet werden.

ExportEntsprechender Import
export const MAX = 30;import { MAX } from "./limits.js";
export default class Circle {}import Circle from "./shapes.js";
Ein Standardexport und das benannte round2import Circle, { round2 } from "./shapes.js";

Ein Modul kann viele benannte Exporte, aber höchstens einen Standardexport haben. Benannte Importe verwenden den exportierten Namen in geschweiften Klammern; den lokalen Namen für einen Standardimport wählt der Importeur. import { Circle } fordert nicht den Standardexport an, auch wenn die exportierte Klasse Circle heißt.

Benenne um, gruppiere und reexportiere

import { circleArea as areaOfCircle } from "./geometry.js"; gibt einer importierten Funktion einen anderen lokalen Namen. export { circleArea as area }; ändert ihren exportierten Namen. Eine Exportliste kann auch Deklarationen verfügbar machen, die zuvor in der Datei erstellt wurden.

import * as geometry from "./geometry.js"; erstellt ein Modulnamensraumobjekt. Rufe geometry.circleArea(3) auf. Ein Namensraum enthält einen Standardexport unter der Eigenschaft default, sofern das Modul einen hat.

Eine Datei kann die Exporte anderer Dateien zusammenfassen: export { circleArea } from "./geometry.js"; leitet einen benannten Export weiter. export * from "./geometry.js"; leitet benannte Exporte weiter, aber nicht den Standardexport dieses Moduls.

Verstehe gemeinsame Auswertung und Live-Bindungen

Module laufen im strikten Modus und haben auf oberster Ebene undefined als this. Abhängigkeiten werden vor dem eigenen Rumpf des importierenden Moduls ausgewertet. Wird dasselbe aufgelöste Modul aus mehreren Dateien importiert, werden ein einmal ausgewertetes Modul und sein Zustand gemeinsam genutzt.

Angenommen, ein Modul exportiert let count = 0 und increment() ändert den Wert. Nachdem ein Importeur increment() aufgerufen hat, ergibt sein importiertes count beim Lesen 1. Importe sind Live-Bindungen, keine Momentaufnahmen. Der Importeur kann der Bindung selbst keinen neuen Wert zuweisen. Ist ein Export ein Objekt, kann dennoch eine seiner Eigenschaften geändert werden, und andere Importeure sehen die Änderung.

Statische Importdeklarationen gehören auf die oberste Ebene des Moduls. Ein statischer Import innerhalb eines if oder einer Funktion ist ein Syntaxfehler; dynamisches import() übernimmt das spätere Laden. Füge .js in relative ES-Modulpfade für Browser und Node.js ein: Diese Ladesysteme ergänzen die Endung nicht. Ein Pfadfehler oder eine Verwechslung von benanntem und Standardexport verhindert das Laden des Moduls. Korrigiere daher den Import, bevor du im Code, der danach laufen sollte, nach einem Fehler suchst.

Wichtige Erkenntnisse

  • Module halten Deklarationen auf oberster Ebene lokal, sofern sie nicht exportiert werden.
  • Benannte Importe verwenden geschweifte Klammern; ein Standardimport verwendet keine.
  • Ein Namensraum gruppiert Exporte, während Reexporte die Schnittstelle eines Moduls weiterleiten.
  • Importe sind schreibgeschützte Live-Bindungen an gemeinsam genutzten Modulzustand.
  • Statische Importe gehören auf die oberste Ebene und relative ES-Modulpfade benötigen Dateiendungen.

2.2 Lade Module in Browsern und Node.js

Dieselbe ES-Modulsyntax läuft im Browser und in Node.js. Jede Umgebung muss dennoch wissen, dass eine Datei ein Modul ist, und jede hat ihre eigene Art, die angeforderten Pfade aufzulösen.

Starte ein Browsermodul
<script type="module" src="main.js"></script>

Lade nur das Einstiegsmodul mit einem script-Tag. Seine Importe rufen die anderen Dateien automatisch ab. Modulskripte ohne async werden verzögert ausgeführt: Sie laufen nach dem Parsen des HTML in Dokumentreihenfolge. Die Seitenelemente, auf die sie zugreifen, sind dann verfügbar.

Stelle den Ordner mit einem lokalen Server wie python3 -m http.server oder npx serve über HTTP bereit und öffne dessen Localhost-Adresse. Das Öffnen der HTML-Datei vom Datenträger führt wegen der Sicherheitsregeln des Browsers meist dazu, dass Modulanfragen fehlschlagen. Der Server muss JavaScript außerdem mit einem geeigneten MIME-Typ wie text/javascript zurückgeben.

Moduldeklarationen werden nicht global. Ein Inline-Handler wie onclick="save()" kann eine modullokale Funktion nicht finden. Registriere den Handler stattdessen aus JavaScript heraus:

const button = document.querySelector("#save");
function save() { console.log("Saved"); }
button.addEventListener("click", save);
Löse Pfade und Paketnamen auf

Der Modulbezeichner ist die Zeichenkette, die das Modul benennt. ./geometry.js ist relativ zur importierenden Datei; ../geometry.js führt einen Ordner nach oben. Ein mit / beginnender Pfad beginnt im Stammverzeichnis der Website, während eine vollständige HTTPS-URL den vollständigen Ort angibt.

Ein bloßer Name wie "date-fns" hat kein Pfadpräfix. Ein Browser kann dafür nicht node_modules durchsuchen. Eine vor den Modulskripten platzierte Import-Map ordnet einem bloßen Namen eine URL zu. Ein Entwicklungsserver oder Bundler kann stattdessen installierte Pakete auflösen und für den Browser vorbereiten. Die Installation eines Pakets allein ändert das Ladesystem des Browsers nicht.

Lege das Modulformat für Node.js ausdrücklich fest
Datei oder EinstellungNode.js-Format
.mjsES-Modul
.cjsCommonJS
.js unter "type": "module"ES-Modul
.js unter "type": "commonjs"CommonJS

Node.js liest type aus der nächstgelegenen übergeordneten package.json. Ohne ausdrücklichen Typ können aktuelle Versionen ES-Modulsyntax in einer ansonsten mehrdeutigen .js-Datei erkennen. Setze in einem neuen ES-Modulprojekt "type": "module", damit sich die Werkzeuge über das vorgesehene Format einig sind. Die Endungen .mjs und .cjs haben Vorrang vor dieser Einstellung.

Mit den drei Dateien des Kreisbeispiels und { "type": "module" } gibt node main.js den Wert 28.27 aus. Dieselben Dateien funktionieren über ein Browsermodulskript, das über HTTP bereitgestellt wird.

Erkenne CommonJS und eingebaute Module

CommonJS ist das ältere Modulsystem von Node.js. Es verwendet require() zum synchronen Laden und module.exports zum Bereitstellen von Werten. Ein ES-Modul kann module.exports eines CommonJS-Pakets als Standardexport importieren. Aktuelles Node.js kann auch synchrone ES-Modulgraphen mit require laden; Top-Level-await in diesem Graphen verhindert das synchrone Laden.

Verwende in einem ES-Modul import { readFile } from "node:fs/promises"; für ein eingebautes Node.js-Modul. require, module und __dirname sind CommonJS-Variablen, keine globalen ES-Modulvariablen. import.meta.url liefert die URL des Moduls; neuere Node.js-Versionen stellen für lokale Dateimodule auch import.meta.dirname bereit.

Wird eine Importanweisung abgelehnt, weil sie außerhalb eines Moduls steht, prüfe die Einstellung des Ladesystems: type="module" im Browser-HTML oder den Pakettyp beziehungsweise die Dateiendung in Node.js.

Wichtige Erkenntnisse

  • Ein Browser-Einstiegsmodul verwendet type="module" und wird normalerweise verzögert ausgeführt.
  • Verwende einen lokalen Server und registriere Event-Handler aus dem Modul heraus.
  • Browser benötigen eine Import-Map oder Buildwerkzeuge, um bloße Paketnamen aufzulösen.
  • Node.js verwendet Dateiendungen und das Feld type des nächstgelegenen Pakets.
  • CommonJS verwendet require und module.exports; ES-Module verwenden import und export.

2.3 Lade Funktionen bei Bedarf und trenne Zuständigkeiten

Ein statischer Import deklariert eine Abhängigkeit, die beim Laden eines Moduls benötigt wird. Ein dynamischer Import ist ein Ausdruck: Er beginnt mit dem Laden, wenn die Ausführung ihn erreicht, und gibt ein Promise zurück. Verwende ihn für eine Funktion, die bei vielen Besuchen gar nicht benötigt wird.

Warte auf das Namensraumobjekt
const button = document.querySelector("#show-chart");
button.addEventListener("click", async () => {
  try {
    const { drawChart } = await import("./chart.js");
    drawChart(measurements);
  } catch (err) {
    console.error("Could not load the chart module", err);
  }
});

Hier sind measurements die Daten, die die Seite gesammelt hat. Der erste Klick lädt das Diagrammmodul und ruft seine exportierte Funktion auf. Spätere Klicks verwenden das ausgewertete Modul erneut. Das Promise kann bei einem Lade- oder Auswertungsfehler abgelehnt werden, daher fängt der Handler den Fehler ab.

import("./chart.js").drawChart versucht, eine Eigenschaft des Promise zu lesen, nicht des geladenen Moduls. Warte auf das Promise oder verwende .then. Greife bei einem Standardexport auf die Eigenschaft default des Namensraums zu: const { default: Chart } = await import("./chart.js");. Anders als eine statische Deklaration kann dieser Ausdruck innerhalb einer Funktion oder Bedingung stehen und sein Pfad kann zur Laufzeit berechnet werden.

Warte während der Moduleinrichtung

Ein ES-Modul kann Top-Level-await außerhalb einer Funktion verwenden:

const response = await fetch("./config.json");
export const config = await response.json();

Module, die von diesem Modul abhängen, warten, bis seine Auswertung abgeschlossen ist, bevor ihre eigenen Rümpfe ausgeführt werden. Unabhängige Module können fortfahren. Eine langsame Konfigurationsanfrage verzögert daher die davon abhängigen Module, aber nicht unbedingt jeden Teil des Programms. Klassische Skripte und CommonJS erlauben kein Top-Level-await; verwende diese Modulfunktion für Vorbereitungen, die abhängige Module tatsächlich zuerst benötigen.

Gib jedem Modul eine klare Aufgabe

Eine Aufgabenanwendung kann diese Zuständigkeiten verwenden:

ModulZuständigkeit
todo.jsDie Klasse Todo exportieren
storage.jsDaten über localStorage laden und speichern
ui.jsDie Liste auf der Seite rendern
main.jsModule und Event-Handler verbinden

Die Daten- und Speichermodule importieren die Benutzeroberfläche nicht. Sie können getestet und wiederverwendet werden, ohne Seitenelemente zu erstellen. Wenn Berechnung und Speicherung außerhalb von Event-Handlern bleiben, lassen sich Fehler auch leichter eingrenzen.

Privater Zustand auf oberster Ebene wird von allen Importeuren gemeinsam genutzt. In let nextId = 1; export function createId() { return nextId++; } bleibt die Variable privat, während die Funktion kontrollierten Zugriff ermöglicht. Zwei Importeure, die sie jeweils einmal aufrufen, erhalten 1 und 2, nicht zwei separate Zähler, die bei 1 beginnen.

Steuere die Arbeit beim Import

import "./setup.js"; ist ein Seiteneffektimport: Er lädt das Modul und wertet es aus, ohne lokale Namen anzufordern. Seiteneffekte können für die Einrichtung nützlich sein, aber ein wiederverwendbares Modul lässt sich leichter testen, wenn es auf oberster Ebene Funktionen und Werte definiert und seine Funktionen die Arbeit ausdrücklich starten.

Eine Index- oder Barrel-Datei sammelt Reexporte. Sie kann eine Schnittstelle vereinfachen, aber große Barrel-Dateien können zusätzlichen Code einbeziehen und einen Zyklus verbergen. Eine zyklische Abhängigkeit entsteht, wenn Module direkt oder über andere Module voneinander abhängen. Ein Zyklus kann funktionieren, aber das Lesen einer Bindung, bevor das exportierende Modul sie initialisiert, verursacht einen ReferenceError. Verschiebe gemeinsam genutzte Definitionen in ein drittes Modul, das beide Seiten importieren, um diesen Abhängigkeitszyklus aufzulösen.

Wichtige Erkenntnisse

  • import() gibt ein Promise für einen Modulnamensraum zurück und kann innerhalb einer Funktion ausgeführt werden.
  • Warte auf das dynamische Laden und behandle abgelehnte Promises.
  • Top-Level-await verzögert die Auswertung abhängiger Module.
  • Trenne Daten, Speicherung, Rendern und die Verknüpfung von Ereignissen in Module mit klaren Aufgaben.
  • Ein ausgewertetes Modul kann privaten Zustand enthalten, den alle seine Importeure gemeinsam nutzen.
  • Verschiebe gemeinsam genutzte Definitionen in ein drittes Modul, um eine zyklische Abhängigkeit aufzulösen.
3

Führe ein reproduzierbares Projekt mit npm aus

Ein Projekt benötigt eine klare Beschreibung seiner Befehle und der Pakete, von denen es abhängt. npm hält diese Informationen in Paketdateien fest und installiert den Code, den diese Dateien beschreiben. Lerne, Skripte vor ihrer Ausführung zu lesen, Entwicklungswerkzeuge von Produktabhängigkeiten zu unterscheiden und Versionsbereiche zusammen mit einer Lockdatei zu verwenden. So kann ein anderer Computer das Projekt wiederherstellen, ohne einen installierten Paketordner zu kopieren.

3.1 Beschreibe ein npm-Projekt und führe es aus

npm ist der mit Node.js gelieferte Paketmanager. Der Name bezeichnet sowohl ein Kommandozeilenwerkzeug als auch dessen öffentliche Paket-Registry. Ein Paket ist ein durch package.json beschriebener Ordner; der Stammordner eines Projekts ist der Ordner, der diese Datei enthält.

Erstelle die Projektbeschreibung

Führe node -v und npm -v aus, um die installierten Werkzeuge zu prüfen. Wechsle in den vorgesehenen Projektordner, bevor du npm init ausführst. Der interaktive Befehl stellt Fragen; npm init -y übernimmt die Standardwerte. Bearbeite dann die Datei, um das Projekt zu beschreiben.

{
  "name": "shape-lab",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "start": "node src/main.js",
    "test": "node --test",
    "lint": "eslint ."
  },
  "dependencies": {},
  "devDependencies": {}
}

Dies ist JSON, kein JavaScript-Objektliteral. Schlüssel und Zeichenketten stehen in doppelten Anführungszeichen. Kommentare und nachgestellte Kommas sind ungültig. Ein Parserfehler kann npm stoppen, bevor es einen Befehl ausführt.

Der name wird kleingeschrieben und ist URL-tauglich; veröffentlichte Paketnamen haben höchstens 214 Zeichen. version beschreibt dieses Projekt, nicht seine Node.js-Version. private: true verhindert eine versehentliche Veröffentlichung über npm. type: "module" sorgt dafür, dass Node.js die .js-Dateien des Pakets als ES-Module lädt.

Veröffentlichte Pakete können mit main und exports Einstiegspunkte für ihre Nutzer definieren. Ein optionaler Eintrag engines wie { "node": ">=22" } gibt unterstützte Node.js-Versionen an. Lies diese Anforderungen, wenn ein Projekt auf einer älteren Installation fehlschlägt.

Nutze Skripte als Aufgabenmenü

npm run listet verfügbare Skripte auf. In diesem Beispiel führt npm run lint den Befehl eslint . aus, npm start startet die Anwendung und npm test führt den Testrunner aus. start und test haben diese Kurzformen; andere Aufgabennamen verwenden normalerweise npm run.

npm fügt das Verzeichnis node_modules/.bin des Projekts vorübergehend zum Suchpfad für Befehle hinzu. Ein lokal installiertes Werkzeug kann daher direkt in einem Skript genannt werden. Alle, die das Projekt nutzen, führen dasselbe festgehaltene Werkzeug aus, statt sich auf eine globale Installation zu verlassen.

Zusätzliche Argumente folgen auf --: npm run lint -- --fix übergibt --fix an ESLint. Das Skript gibt der Aufgabe einen stabilen Namen, auch wenn das Team das dahinterstehende Werkzeug ändert. Beginne mit dem Feld scripts, wenn du lernst, wie du an einem unbekannten Projekt arbeitest.

Lies Versionsnummern

Die semantische Versionierung verwendet HAUPTVERSION.NEBENVERSION.PATCH. Ausgehend von 2.4.1 wird eine kompatible Fehlerkorrektur zu 2.4.2, eine kompatible Funktion zu 2.5.0 und eine inkompatible Änderung zu 3.0.0. Ein Wechsel auf eine neue Hauptversion kann Änderungen an Code erfordern, der das Paket verwendet. Vor 1.0.0 befindet sich ein Projekt in früher Entwicklung und Veröffentlichungen können sich freier ändern.

Führe gelegentlich einen Paketbefehl aus

npx serve führt den installierten Befehl aus, wenn er lokal verfügbar ist. Andernfalls kann npx nachfragen, ob es das Paket vorübergehend herunterladen und ausführen soll. Das ist für ein Werkzeug nützlich, das keine dauerhafte Projektabhängigkeit werden muss. Prüfe den genauen Paketnamen und die Vertrauenswürdigkeit des Codes, bevor du ihn installierst oder ausführst: Paketbefehle und Installationsskripte können mit deinen Berechtigungen ausgeführt werden.

Ein im falschen Ordner ausgeführter Befehl kann fehlschlagen, weil package.json fehlt, oder eine Installation kann Paketdateien an einem unbeabsichtigten Ort erstellen. Prüfe zuerst den aktuellen Ordner. Halte Skripte verständlich und vermeide betriebssystemspezifische Befehlskniffe, wenn das Projekt auf mehreren Systemen laufen muss.

Wichtige Erkenntnisse

  • package.json beschreibt Projekt, Skripte und Abhängigkeiten mit gültigem JSON.
  • private: true verhindert die Veröffentlichung über npm; type legt das Node.js-Modulformat fest.
  • Nutze npm-Skripte, um lokal installierte Werkzeuge einheitlich auszuführen.
  • Semantische Versionen unterscheiden inkompatible Änderungen, kompatible Funktionen und Fehlerkorrekturen.
  • npx kann einen lokalen Befehl ausführen oder einen vorübergehend herunterladen.

3.2 Installiere und aktualisiere die richtigen Paketversionen

Eine Abhängigkeit ist Code, auf den ein Projekt angewiesen ist. npm hält direkte Abhängigkeiten in package.json fest, installiert Pakete in node_modules und verzeichnet den genauen installierten Abhängigkeitsbaum in package-lock.json.

Trenne Produktcode von Entwicklungswerkzeugen

npm install date-fns fügt ein Laufzeitpaket zu dependencies hinzu. npm install --save-dev eslint fügt ein Entwicklungswerkzeug zu devDependencies hinzu; -D ist die Kurzform. Linter, Codeformatierer, Testrunner, Bundler und TypeScript gehören normalerweise in die Entwicklungsliste.

Wenn ein anderes Projekt ein veröffentlichtes Paket installiert, installiert npm dessen Abhängigkeiten, aber nicht dessen Entwicklungsabhängigkeiten. Eine Browseranwendung kann Laufzeitabhängigkeiten dennoch in ihre endgültigen Dateien bündeln, obwohl das Buildwerkzeug selbst eine devDependency ist.

npm install ohne Paketnamen installiert die für das Projekt aufgeführten Abhängigkeiten. npm uninstall <package> entfernt ein Paket und seinen Eintrag. Nach der Installation von date-fns können Node.js und Buildwerkzeuge import { format } from "date-fns"; auflösen. Ein einfacher Browser benötigt weiterhin eine Auflösungshilfe wie eine Import-Map oder einen Entwicklungsserver.

Lies den erlaubten Bereich
EintragErlaubte stabile Versionen
^4.17.21Mindestens 4.17.21, unter 5.0.0
~4.17.21Mindestens 4.17.21, unter 4.18.0
4.17.21Genau 4.17.21
^0.3.1Mindestens 0.3.1, unter 0.4.0

Das Caret ist der übliche Standard von npm. Bei Versionen ab 1.0.0 erlaubt es kompatible Aktualisierungen der Neben- und Patchversion. Unter 1.0.0 ist es strenger. Für ^2.3.0 passen 2.3.5 und 2.9.0; 2.2.9 ist zu alt und 3.0.0 überschreitet die Grenze zur nächsten Hauptversion.

Ein erlaubter Bereich bezeichnet keine einzelne installierte Version. Das tut die Lockdatei, einschließlich der transitiven Abhängigkeiten, also der Pakete, die deine ausgewählten Pakete benötigen.

Stelle eine Installation wieder her

Gib package.json und package-lock.json zusammen mit dem Projekt weiter. Lass npm die Lockdatei verwalten. Der generierte Ordner node_modules kann neu erstellt werden und wird nicht weitergegeben.

Verwende npm install während der Entwicklung, wenn sich die Abhängigkeitseinträge ändern können. Verwende npm ci für eine saubere, reproduzierbare Installation: Es benötigt die Lockdatei, entfernt ein vorhandenes node_modules, installiert den festgelegten Baum und schreibt keine der beiden Paketdateien neu. Es schlägt fehl, wenn Paketdatei und Lockdatei nicht übereinstimmen. Behebe diese Abweichung während der Entwicklung bewusst; das Löschen der Lockdatei kann viele Versionen unbemerkt ändern.

Aktualisiere aus einem bestimmten Grund

npm outdated vergleicht die aktuelle, die gewünschte und die neueste Version. Die gewünschte Version ist die neueste, die der deklarierte Bereich erlaubt; die neueste kann eine Hauptversion außerhalb dieses Bereichs sein. npm update aktualisiert innerhalb der Bereiche und hält den resultierenden Baum fest. Um bewusst zu einer neuen Hauptversion zu wechseln, lies das Änderungsprotokoll, führe npm install <package>@latest aus und prüfe das Projekt mit seinen Tests.

Installiere Projektwerkzeuge lokal, damit ihre Versionen festgehalten werden. Prüfe vor dem Hinzufügen einer weiteren Abhängigkeit deren Pflege, Verbreitung und Lizenz sowie die Frage, ob eine eingebaute Funktion das Problem bereits löst. structuredClone() deckt unterstützte Anwendungsfälle für tiefe Kopien ab; Intl.DateTimeFormat formatiert Datumsangaben ohne Datumspaket.

npm audit meldet bekannte Sicherheitslücken in installierten Versionen. Lies den Bericht, um den betroffenen Code und seine Nutzung zu verstehen. npm audit fix kann kompatible Korrekturen anwenden, beweist aber weder, dass jede Sicherheitslücke behoben ist, noch, dass eine Aktualisierung das Verhalten des Projekts erhält.

Wichtige Erkenntnisse

  • Verwende dependencies für Laufzeitcode und devDependencies für Entwicklungs- und Buildwerkzeuge.
  • Versionsbereiche erlauben bestimmte Versionen; die Lockdatei hält die genauen installierten Versionen fest.
  • Gib beide Paketdateien weiter und erstelle node_modules neu.
  • npm ci installiert die in der Lockdatei festgelegten Pakete, ohne die Datei zu ändern, und lehnt nicht übereinstimmende Paketdateien ab.
  • npm update bleibt innerhalb deklarierter Bereiche; für den Wechsel zu einer neuen Hauptversion ist eine bewusste Entscheidung nötig.
  • Lies Sicherheitsberichte und prüfe das Verhalten nach Aktualisierungen von Abhängigkeiten.
4

Prüfe und baue Code mit Entwicklerwerkzeugen

Verschiedene Werkzeuge beantworten verschiedene Fragen zu einem Projekt. Ein Linter sucht nach verdächtigem Code, ein Codeformatierer ordnet ihn, Tests prüfen sein Verhalten und ein Build bereitet Browserdateien für die Veröffentlichung vor. Ein Entwicklungsserver hält den Bearbeitungsablauf schnell. Lerne, was jedes Ergebnis aussagt und was es ungeprüft lässt, damit ein erfolgreicher Formatierungsbefehl oder eine funktionierende Entwicklungsseite nicht als Beleg dafür gilt, dass die ganze Anwendung funktioniert.

4.1 Finde Codeprobleme und formatiere einheitlich

Ein Linter liest Quellcode, ohne ihn auszuführen, und meldet wahrscheinliche Fehler oder riskante Muster. Ein Codeformatierer gestaltet das Layout einheitlich um. ESLint und Prettier arbeiten oft zusammen, weil diese Aufgaben unterschiedliche Probleme lösen.

Konfiguriere die Prüfungen

npm init @eslint/config@latest stellt Fragen zum Projekt, installiert Entwicklungspakete und erstellt eine Konfigurationsdatei. Aktuelles ESLint verwendet eine flache Konfiguration, üblicherweise in eslint.config.js.

import js from "@eslint/js";
import globals from "globals";

export default [
  js.configs.recommended,
  {
    languageOptions: { globals: globals.browser },
    rules: {
      eqeqeq: "error",
      "no-unused-vars": "warn",
    },
  },
];

Die empfohlene Konfiguration aktiviert Regeln zur Fehlersuche. Die globalen Browsernamen teilen ESLint mit, dass Namen wie document existieren. So wird eine tatsächlich vorhandene Funktion der Umgebung nicht als undefinierter Name behandelt.

Die Schweregrade der Regeln sind "off", "warn" und "error", auch als 0, 1 und 2 geschrieben. Fehler führen zu einem Fehlercode; Warnungen allein lassen den Befehl standardmäßig nicht fehlschlagen. Auch wenn das Skript erfolgreich endet, enthält eine Warnung Informationen, die du lesen solltest.

Lies einen Linter-Bericht
function total(items) {
  let sum = 0;
  let unused = 5;
  for (const item of items) {
    if (item.quantity == "2") sum += item.price;
  }
  return summ;
}

Mit der obigen Konfiguration werden fünf Probleme gemeldet. total wird nie verwendet. sum wird aktualisiert, aber sein Wert wird über diese Aktualisierungen hinaus nie verwendet. unused wird nicht verwendet. Die Regel eqeqeq beanstandet ==, und no-undef erkennt das falsch geschriebene summ. Ein Aufruf dieser Funktion würde an diesem undefinierten Namen fehlschlagen, aber der Linter kann ihn ohne Aufruf finden.

Beginne im Bericht mit dem Namen der Regel und der Fundstelle. Korrigiere das beabsichtigte Verhalten und führe den Befehl erneut aus. npm run lint -- --fix fordert sichere automatische Korrekturen an, wenn das Projekt ein Skript lint hat. Der Befehl kann nicht für jede Warnung die richtige Programmlogik bestimmen. Deaktiviere eine Regel für eine Zeile nur, wenn es einen Grund gibt, und halte diesen neben dem Kommentar fest.

Überlasse das Layout einem Codeformatierer
npm install --save-dev --save-exact prettier
npx prettier . --write
npx prettier . --check

--write ändert Dateien; --check meldet Formatierungsunterschiede, ohne Dateien zu ändern. Mit den Standardeinstellungen wird aus const point={x:1,y:2} der Code const point = { x: 1, y: 2 };. Optionen wie "singleQuote": true stehen in .prettierrc.

WerkzeugHauptfrage
ESLintEnthält dieser Code ein Muster, das eine Regel beanstandet?
PrettierHat der Code das gewählte Layout?
TestrunnerZeigt der Code das erwartete Verhalten?

Die empfohlenen ESLint-Regeln schreiben das Layout von Prettier nicht vor, sodass diese Einrichtung Formatierungskonflikte vermeidet. Fügt eine andere ESLint-Konfiguration widersprüchliche Stilregeln hinzu, schaltet eslint-config-prettier diese Regeln aus. Werden zwei konkurrierende Codeformatierer ausgeführt, können sich Dateien ständig hin und her ändern.

Füge Skripte lint und format hinzu, damit sich Prüfungen leicht wiederholen lassen. Editor-Erweiterungen können nach der Konfiguration während der Eingabe Diagnosen anzeigen und beim Speichern formatieren. Beide Werkzeuge überspringen node_modules standardmäßig; füge generierte Ausgaben wie dist zu den passenden Ignoriereinstellungen hinzu. Eine Funktion ohne Linter-Meldungen kann trotzdem den Umfang berechnen, obwohl sie die Fläche berechnen sollte; das Verhalten braucht Tests.

Wichtige Erkenntnisse

  • Ein Linter findet konfigurierte Quellcodeprobleme, ohne das Programm auszuführen.
  • Der ESLint-Schweregrad für Fehler lässt den Befehl fehlschlagen; Warnungen tun das standardmäßig nicht.
  • Prettier ändert das Layout mit --write und prüft es mit --check.
  • Verwende kompatible Linter- und Formatierungsregeln sowie Tests für das Verhalten.

4.2 Entwickle lokal und baue Browserdateien

Ein Browser kann einige ES-Module direkt laden, aber größere Projekte verwenden auch installierte Pakete und Dateien, die transformiert werden müssen. Ein Entwicklungsserver bereitet Dateien während der Bearbeitung vor. Ein Bundler folgt Abhängigkeiten, um für die Veröffentlichung geeignete Dateien zu erstellen.

Durchlaufe den Vite-Zyklus
npm create vite@latest shape-lab
cd shape-lab
npm install
npm run dev
npm run build
npm run preview

Wähle für dieses Projekt die JavaScript-Vorlage Vanilla. Der Generator stellt Entwicklungs- und Buildskripte bereit. npm run dev gibt eine lokale Adresse aus, häufig http://localhost:5173. Öffne diese Adresse während der Bearbeitung. In Vite ist index.html der Einstiegspunkt und lädt /src/main.js normalerweise mit einem Modulskript.

Der Entwicklungsserver löst Paketnamen auf und transformiert Dateien nach Bedarf. Das Speichern einer Datei löst eine Aktualisierung aus. Hot Module Replacement, kurz HMR, ersetzt ein geändertes Modul auf der laufenden Seite; bei unterstützten Aktualisierungen kann der Zustand erhalten bleiben, statt ein vollständiges Neuladen zu erzwingen.

npm run build schreibt optimierte Ausgaben nach dist. npm run preview stellt diese Ausgabe lokal bereit, damit du den tatsächlichen Produktionsbuild prüfen kannst. Die Vorschau benötigt einen vorhandenen Build und erstellt keinen neuen. Bearbeite die Quelldateien, da ein weiterer Build die generierte Ausgabe ersetzt.

Verstehe die Änderungen im Produktionsbuild
BuildfunktionZweck
BündelungModule zu weniger Browserdateien zusammenfassen
Tree ShakingCode entfernen, den der Build nachweislich nicht benötigt
MinifizierungGröße durch Entfernen des Layouts und Verkürzen von Namen verringern
InhaltshashesDateinamen bei Inhaltsänderungen ändern und so das Caching unterstützen
Code-SplittingTeile des Codes in separaten Abschnitten halten, die später geladen werden können

Ein Hilfsmodul kann zum Beispiel sowohl formatArea als auch formatVolume exportieren. Wenn nur formatArea verwendet wird und das Entfernen des anderen Codes sicher ist, kann Tree Shaking formatVolume weglassen. Statische Importe und Exporte machen Abhängigkeiten sichtbar. Seiteneffekte eines Moduls auf oberster Ebene müssen möglicherweise erhalten bleiben, auch wenn keiner seiner Exporte verwendet wird.

Ein dynamisches import() gibt dem Buildwerkzeug eine Grenze für das spätere Laden. Buildwerkzeuge können dafür separate Abschnitte erstellen; deren Aufteilung hängt vom Build ab, sodass ein Quellmodul nicht immer zu genau einer Ausgabedatei wird.

Ein Name wie assets/index-4f2a9c1b.js ändert sich mit seinem Inhalt und ermöglicht so langlebige Browser-Caches, ohne nach einer Aktualisierung eine alte Datei auszuliefern. Eine Source Map verbindet Stellen in der generierten Ausgabe mit ursprünglichen Quellcodezeilen und erleichtert damit Stacktraces und das Debuggen, wenn solche Zuordnungen verfügbar sind.

Binde Ressourcen und öffentliche Konfiguration ein

Vite verarbeitet auch Ressourcen: import "./style.css"; bindet Stile ein und import logoUrl from "./logo.png"; liefert die endgültige URL des Bildes. Der Build kann diese Verweise aktualisieren, damit sie zu den generierten Dateinamen passen.

Lies Modusinformationen über import.meta.env.MODE. Die Standardwerte sind "development" für die Entwicklung und "production" für einen Build; ein benutzerdefinierter Modus kann einen anderen Namen verwenden. Benutzerdefinierte Umgebungswerte, die mit VITE_ beginnen, werden dem Browsercode standardmäßig zur Verfügung gestellt. Alles, was an den Browser ausgeliefert wird, ist öffentlich: Bewahre geheime Schlüssel und Passwörter auf einem Server auf, außerhalb des Browsercodes und offengelegter Umgebungsvariablen.

Prüfe nicht nur die Entwicklungsseite. Erstelle vor der Veröffentlichung einen Build und sieh ihn dir in der Vorschau an, um Probleme in der transformierten Ausgabe und bei Ressourcenpfaden zu finden. dist/index.html direkt vom Datenträger zu öffnen, entspricht nicht der Bereitstellung der Website über HTTP. Eine kleine Seite mit wenigen einfachen Modulen benötigt möglicherweise nur einen statischen Server und kein vollständiges Buildwerkzeug.

Wichtige Erkenntnisse

  • Ein Entwicklungsserver löst Dateien während der Bearbeitung auf und transformiert sie; ein Produktionsbuild erstellt die Ausgabe für die Veröffentlichung.
  • HMR kann geänderten Code ersetzen und dabei unterstützten Seitenzustand erhalten.
  • Tree Shaking entfernt Code nur, wenn der Build ihn sicher weglassen kann.
  • Inhaltshashes unterstützen das Caching und Source Maps verbinden die Ausgabe mit dem Quellcode.
  • Erstelle zuerst den Build und sieh dir dann die generierte Ausgabe lokal in der Vorschau an.
  • Browser-Bundles und offengelegte Umgebungswerte sind öffentlich.

4.3 Teste Verhalten mit Assertions

Ein automatisierter Test führt Code mit bekannten Eingaben aus und prüft das Ergebnis mit Assertions. Ein Unittest konzentriert sich auf einen kleinen Teil, etwa eine Funktion oder Methode. Der Testrunner findet Tests, führt sie aus, meldet Fehler und endet mit einem Fehlercode, wenn ein Test fehlschlägt.

Vorbereiten, ausführen, prüfen

Bereite die Eingabe vor, führe den Code aus und prüfe das erwartete Ergebnis. Ein hilfreicher Testname beschreibt das Verhalten. Für eine Rechteckklasse, deren Konstruktor eine negative Seitenlänge ablehnt:

import { test } from "node:test";
import assert from "node:assert/strict";
import { Rectangle } from "./rectangle.js";

test("area multiplies width by height", () => {
  assert.equal(new Rectangle(3, 4).area(), 12);
});
test("rejects a negative width", () => {
  assert.throws(() => new Rectangle(-1, 4), RangeError);
});

Die erste Assertion prüft 12 cm², ein unabhängig bekanntes Ergebnis. Die zweite übergibt eine Funktion an assert.throws, damit die Assertion den Fehler erfassen kann. Bei der Ausführung von node --test werden Dateien mit Namen wie rectangle.test.js gefunden; ein Paketskript "test": "node --test" ermöglicht npm test.

Der strikte Assertion-Modus verwendet für assert.equal die Methode Object.is ohne implizite Typumwandlung. assert.deepEqual vergleicht den Inhalt von Objekten und Arrays. Verschiedene Arrays mit denselben Werten sind nicht dasselbe Objekt, daher ist ein strikter Identitätsvergleich die falsche Prüfung auf gleichen Inhalt.

Nutze entsprechende Konzepte in Vitest
import { describe, it, expect } from "vitest";
import { Rectangle } from "./rectangle.js";

describe("Rectangle", () => {
  it("computes the area", () => {
    expect(new Rectangle(3, 4).area()).toBe(12);
  });
  it("rejects a negative width", () => {
    expect(() => new Rectangle(-1, 4)).toThrow(RangeError);
  });
});

Vitest verwendet describe zum Gruppieren und it für einzelne Tests. Führe npx vitest aus, um Änderungen zu überwachen, oder npx vitest run für einen einmaligen Durchlauf. Jest bietet einen ähnlichen Stil. Verwende toEqual für Inhalte und toBe für Identität oder primitive Werte.

Beziehe Grenzwerte und numerische Schranken ein

Teste die genauen Endpunkte eines erlaubten Bereichs ebenso wie Eingaben knapp außerhalb. Ein Thermostat, das 10 bis 30 °C akzeptiert, benötigt Tests, die 10 und 30 akzeptieren, sowie Tests, die 9,5 und 30,5 ablehnen. Ergänze separate Prüfungen für nicht numerische und nicht endliche Werte, wenn die Schnittstelle sie ablehnt. Tests sollten nicht von einem durch einen vorherigen Test veränderten Objekt oder von der Ausführungsreihenfolge abhängen.

Gleitkommaarithmetik stimmt möglicherweise nicht genau mit einem geschriebenen Dezimalwert überein: 0.1 + 0.2 ist 0.30000000000000004. Verwende für eine passende Toleranz assert.ok(Math.abs(actual - expected) < 1e-9). Ein Kreis mit Radius 3 hat eine Fläche von etwa 28,274333882 cm²; toBeCloseTo(28.27, 2) von Vitest prüft die Nähe auf diese Dezimalgenauigkeit. Wähle die Toleranz passend zu dem, was der Test nachweisen soll.

Lerne aus einem Fehlschlag

Lies das benannte Verhalten, den erwarteten und den tatsächlichen Wert sowie die Stelle im Quellcode. Entscheide, ob die Implementierung oder die Erwartung des Tests falsch ist. Schreibe bei der testgetriebenen Entwicklung einen fehlschlagenden Test, implementiere genug, damit er besteht, und verbessere dann den Code, während die Tests weiterhin bestehen.

Exportiere Logik aus Modulen und übergib Eingaben als Argumente. Ein Event-Handler kann dann Seitendaten sammeln und diese Logik aufrufen, statt Berechnungen mit DOM-Arbeit zu vermischen. DOM-abhängiger Code kann einen simulierten Browser wie jsdom verwenden. Warte in einem asynchronen Test auf asynchrone Arbeit, damit der Test nicht vor seinen Prüfungen endet. Ein Test, der lediglich die Formel der Implementierung wiederholt, kann deren Fehler wiederholen; verwende das erwartete Verhalten und unabhängige Beispiele.

Wichtige Erkenntnisse

  • Tests führen Code aus und prüfen mit Assertions unabhängig erwartetes Verhalten.
  • Bereite Eingaben vor, führe den Code aus und prüfe ein Verhalten mit einem hilfreichen Testnamen.
  • Vergleiche den Inhalt verschiedener Arrays oder Objekte, wenn ihre Inhalte gleich sein sollen.
  • Teste Grenzwerte und ungültige Eingaben und verwende geeignete Toleranzen für Gleitkommazahlen.
  • Warte auf asynchrone Arbeit und halte Tests unabhängig von der Ausführungsreihenfolge.
5

Ordne Typen und Frameworks in den Arbeitsablauf ein

TypeScript und Frontend-Frameworks bauen auf den bereits vorgestellten JavaScript-Werkzeugen auf. Typen helfen einem Editor und der Typprüfung, nicht passende Werte vor der Ausführung zu finden. Komponenten helfen, Oberflächen zu gliedern, die Daten gemeinsam nutzen und ändern. Beides ersetzt nicht das Verständnis von Modulen, Abhängigkeiten oder Tests. Nutze die Projektskripte als Wegweiser für das Zusammenspiel dieser Teile und füge Werkzeuge hinzu, wenn ihre Aufgabe klar ist.

5.1 Verstehe, was TypeScript prüft

TypeScript ergänzt JavaScript um statische Typsyntax. Ein Typ beschreibt, welche Art von Wert der Code erwartet. Die Typprüfung nutzt diese Beschreibungen, bevor das Programm läuft, und kann so Fehler aufdecken, bevor Nutzer darauf stoßen.

Prüfe einen Aufruf vor der Ausführung
function area(width: number, height: number): number {
  return width * height;
}
area(3, "4"); // type error: the second argument is a string

Beide Parameter müssen Zahlen sein. Das geschriebene "4" ist eine Zeichenkette, daher meldet die Typprüfung die Abweichung. Einfaches JavaScript würde diese Zeichenkette bei der Multiplikation implizit umwandeln: 3 * "4" ergibt 12. Bei der Addition ergibt 3 + "4" die Zeichenkette "34". Ein Typfehler zeigt eine Abweichung von den vorgesehenen Eingaben an, auch wenn JavaScript den Ausdruck ausführen könnte.

Ein Interface beschreibt die Struktur eines Objekts:

interface Shape {
  name: string;
  area(): number;
}

Eine mit implements Shape deklarierte Klasse muss die angegebenen Eigenschaften und Methoden mit kompatiblen Typen bereitstellen. Die Typprüfung kann bei aktivierter strikter Prüfung auch falsch geschriebene Eigenschaften, falsche Argumentzahlen und mögliche undefined-Werte erkennen.

Trenne Typprüfung und Entfernen der Typen
Werkzeug oder AktionFunktion
tscPrüft Typen und gibt normalerweise JavaScript aus
tsc --noEmitPrüft Typen, ohne Ausgaben zu schreiben
TypeScript-Transformation von ViteEntfernt Typsyntax für die Ausführung
Type Stripping von Node.jsFührt unterstützten entfernbaren TypeScript-Code nach dem Entfernen der Typen aus

Die TypeScript-Projekteinstellungen stehen in tsconfig.json. Ein Vite-Build stellt nicht selbst fest, ob alle Typen korrekt sind. Projekte führen häufig tsc --noEmit separat aus. Aktuelles Node.js kann unterstützte .ts-Dateien direkt ausführen, prüft ihre Typen beim Type Stripping aber ebenfalls nicht.

Behalte Laufzeitprüfungen an Datengrenzen bei

Typannotationen werden vor der Ausführung entfernt. Die Deklaration des erwarteten Typs von Daten aus fetch() oder JSON.parse() überprüft den tatsächlichen Wert nicht. Prüfe externe Daten im laufenden Code, bevor du dich auf sie verlässt. Ein Server kann eine Zeichenkette senden, selbst wenn eine Typdeklaration ein Feld als numerisch bezeichnet.

private und readonly von TypeScript sind Einschränkungen der Typprüfung; sie bieten nicht den privaten Zugriffsschutz von JavaScript mit # zur Laufzeit. Private JavaScript-Felder werden weiterhin geschützt, während das Programm läuft. TypeScript macht ein Programm auch nicht schneller und beweist nicht, dass seine Berechnungen korrekt sind.

Der Typ any schaltet nützliche Prüfungen für einen Wert aus. Er kann eine Fehlermeldung unterdrücken, während der ursprüngliche Fehler bestehen bleibt. Das Korrigieren einer falschen Annahme oder das Hinzufügen einer tatsächlichen Datenprüfung liefert der Typprüfung bessere Informationen.

Führe TypeScript in überschaubaren Schritten ein

Eine JavaScript-Datei kann mit // @ts-check beginnen und JSDoc wie /** @param {number} width */ verwenden, um in unterstützenden Editoren Prüfungen zu erhalten, ohne zu einer .ts-Datei zu werden. Ein Projekt kann später Dateien einzeln umbenennen. Bibliotheken können .d.ts-Typdefinitionen bereitstellen; Definitionen der Community werden häufig unter @types/... verteilt.

Größere, langlebige Projekte erhalten klarere Schnittstellen, sichereres Refactoring und bessere Vervollständigung im Editor. Bei einem kleinen Skript rechtfertigt der Nutzen möglicherweise noch keinen weiteren Buildschritt und keine neue Syntax. Tests bleiben in beiden Fällen nützlich: Eine korrekt typisierte Flächenfunktion kann trotzdem eine falsche Zahl berechnen.

Wichtige Erkenntnisse

  • TypeScript prüft erwartete Werttypen vor der Ausführung.
  • Das Entfernen von Typsyntax ist von der Typprüfung getrennt.
  • Typdeklarationen validieren externe Daten nicht zur Laufzeit.
  • Der Zugriffsschutz mit # in JavaScript wird zur Laufzeit durchgesetzt; TypeScript-private wird statisch geprüft.
  • JSDoc-Prüfung ermöglicht eine schrittweise Einführung, bevor Dateien in TypeScript umgewandelt werden.

5.2 Kombiniere Werkzeuge passend zum Bedarf des Projekts

Eine Bibliothek stellt Code bereit, den dein Programm aufruft. Ein Framework bietet eine Anwendungsstruktur und ruft deinen Code zu den richtigen Zeitpunkten auf. Diese Änderung der Steuerung hilft, größere Oberflächen zu koordinieren, beruht aber weiterhin auf JavaScript, Modulen und einer Projektwerkzeugkette.

Gliedere eine Oberfläche in Komponenten

React, Vue, Svelte und Angular gliedern Benutzeroberflächen mit Komponenten: wiederverwendbaren Teilen wie einer Navigationsleiste oder einem Aufgabeneintrag. Eine Komponente verbindet Markup und Verhalten, oft mit Stilen. Wenn sich ihr Zustand ändert, koordiniert das System für die Benutzeroberfläche die betreffenden Seitenaktualisierungen.

Meta-Frameworks wie Next.js, Nuxt, SvelteKit und Astro ergänzen eine umfangreichere Einrichtung, darunter Routing, Rendern auf dem Server und Buildunterstützung. Ihr genauer Funktionsumfang unterscheidet sich. Kenntnisse über JavaScript-Funktionen, Ereignisse, asynchronen Code und Modulgrenzen helfen beim Erlernen jedes dieser Frameworks.

Eine Seite mit wenigen unabhängigen interaktiven Funktionen kann mit einfachem JavaScript übersichtlich sein. Ein Framework wird nützlich, wenn viele Ansichten sich ändernde Daten gemeinsam nutzen müssen. Wähle es für diesen Bedarf, statt anzunehmen, dass jede Seite die größte Werkzeugkette benötigt.

Verfolge das Zusammenspiel der Werkzeuge

Framework-Pakete werden über npm installiert und als Module importiert. Buildwerkzeuge transformieren Syntax wie JSX oder Framework-spezifische Dateien. TypeScript kann Schnittstellen zwischen Teilen prüfen. Linter-Prüfung, Formatierung und Tests behalten unabhängig von der Wahl der Benutzeroberfläche ihre unterschiedlichen Aufgaben.

Starte ein einfaches Projekt und füge die vom Team verwendeten Werkzeuge hinzu:

npm create vite@latest shape-lab
cd shape-lab
npm install
npm install --save-dev eslint @eslint/js globals prettier vitest

Eine Vite-Vorlage stellt Entwicklungs- und Buildwerkzeuge bereit. Die Installation zusätzlicher Pakete konfiguriert sie nicht: Füge die ESLint-Konfiguration hinzu, erstelle Tests und richte Editor-Erweiterungen für Linter-Prüfung und Formatierung beim Speichern ein. Ein Feld für Skripte kann diese Aufgaben bereitstellen:

{
  "dev": "vite",
  "build": "vite build",
  "preview": "vite preview",
  "lint": "eslint .",
  "format": "prettier . --write",
  "test": "vitest run"
}

Diese Einträge gehören in "scripts" in package.json. Führe während der Bearbeitung npm run dev aus; der Editor kann bei Dateiänderungen prüfen und formatieren. Führe vor dem Weitergeben der Arbeit npm test aus. Führe vor der Veröffentlichung npm run build und npm run preview aus. Der gebaute Ordner dist einer statischen Website kann anschließend zu einem geeigneten statischen Hoster hochgeladen werden.

Finde die Datei, die eine Aufgabe steuert
Datei oder OrdnerAufgabe
package.jsonBefehle und Bereiche direkter Abhängigkeiten
package-lock.jsonGenauer Abhängigkeitsbaum
node_modules/Generierte installierte Pakete
eslint.config.jsLinter-Regeln und Umgebungen
.prettierrcFormatierungsoptionen
vite.config.jsEntwicklungs- und Buildoptionen
tsconfig.jsonEinstellungen für TypeScript-Prüfung und Kompilierung
dist/Generierte Buildausgabe

Beginne bei einem unbekannten Projekt mit package.json: Die Skripte zeigen, wie das Projekt ausgeführt wird, und die Abhängigkeitslisten zeigen, welche Werkzeuge diese Skripte benötigen. Generierte Ordner können neu erstellt werden; Einstellungen und Quellcode erklären, wie das geht.

Lerne neue Werkzeuge einzeln kennen, damit ein Fehler noch eine erkennbare Ursache hat. Nutze die offizielle Dokumentation für die installierte Version, wenn Befehle oder Standardeinstellungen abweichen, denn Veröffentlichungen von Werkzeugen und Frameworks ändern sich häufiger als die JavaScript-Kernsyntax.

Wichtige Erkenntnisse

  • Dein Code ruft eine Bibliothek auf; ein Framework ruft deinen Code innerhalb seiner Struktur auf.
  • Komponenten koordinieren wiederverwendbare Teile der Benutzeroberfläche und sich ändernden Zustand.
  • Framework-Projekte hängen weiterhin von Modulen, Paketen, Builds und Prüfungen ab.
  • Vorlagen und Paketinstallationen konfigurieren nicht jedes zusätzliche Werkzeug automatisch.
  • Lies zuerst die Paketskripte, um den Arbeitsablauf eines Projekts kennenzulernen.
  • Füge Werkzeuge für einen konkreten Bedarf hinzu und prüfe die Dokumentation der installierten Version.

Klassen und Module in JavaScript: Beispiele

5 Interaktive Lektionen

1

Erstelle eine kleine Familie von Objekten

18 Schritte
Erstelle Instanzen, schütze ihren Zustand, spezialisiere Verhalten und verfolge die gemeinsam genutzten Methoden, durch die das Modell funktioniert.
  1. 1
    EinführungBeginne mit Objekten, die Verhalten benötigen

    Ein Programm kann viele Rechtecke speichern, aber jedes benötigt auch Operationen wie Fläche und Umfang. Eine Klasse ermöglicht diesen Objekten, die Operationen gemeinsam zu nutzen und ihre Maße getrennt zu halten.

    Verfolge das Objekt von seiner Erstellung bis zu einem Methodenaufruf. Ergänze dann geschützten Zustand, unterscheide Werte auf Klassenebene und spezialisiere Verhalten durch Vererbung. Untersuche schließlich die Prototypenkette, um zu sehen, wo die gemeinsam genutzten Methoden liegen.

  2. 2
    BeispielInitialisiere eine Instanz

    Der Konstruktor speichert Werte auf dem neuen Objekt. Hier sind die Maße in Zentimetern angegeben:

    class Rectangle {
      constructor(width, height) {
        this.width = width;
        this.height = height;
      }
      area() { return this.width * this.height; }
    }
    const a = new Rectangle(3, 4);
    

    new erstellt a und führt den Konstruktor aus, wobei this darauf verweist. Die beiden Zuweisungen geben a seine eigene Breite und Höhe.

  3. 3
    BeispielRufe gemeinsames Verhalten mit getrennten Daten auf

    Füge const b = new Rectangle(5, 2); hinzu. Beide Objekte können area aufrufen, aber jeder Aufruf liest die Maße des Empfängerobjekts.

    a.area() multipliziert 3 mit 4 und gibt 12 cm² zurück. b.area() multipliziert 5 mit 2 und gibt 10 cm² zurück. Die Zuweisung b.width = 8 ändert nur b, sodass seine nächste Fläche 16 cm² beträgt, während a bei 12 cm² bleibt.

    Die Methode benötigt keine separate Kopie ihres Codes für jedes Rechteck. Die Daten, die sie liest, stammen von this.

  4. 4
    TippBehalte das Objekt in einem Callback

    Eine von einem Objekt getrennte Methode behält ihr Empfängerobjekt nicht dauerhaft:

    const calculate = a.area;
    // calculate(); // this is undefined
    const calculateSafely = () => a.area();
    

    Klassenmethoden laufen im strikten Modus. Der losgelöste Aufruf hat kein Objekt vor dem Punkt, daher schlägt das Lesen von this.width fehl. Der Pfeilfunktions-Wrapper erhält den ursprünglichen Methodenaufruf. a.area.bind(a) ist eine weitere Möglichkeit, einen an a gebundenen Callback zu erzeugen.

  5. 5
    HerausforderungSage einen zweiten Aufruf voraus

    Ein neues Rectangle(6, 2) wird tile zugewiesen. Die Anweisung tile.width = 7 wird ausgeführt. Was gibt tile.area() zurück und warum ändert das kein anderes zuvor erstelltes Rechteck?

    ---reveal---

    Die Methode gibt 14 cm² zurück: Sie liest die aktuelle Breite des Empfängerobjekts, 7 cm, und seine Höhe, 2 cm. Jede Instanz speichert ihre eigenen Maße, sodass eine Änderung von tile.width keine andere Instanz aktualisiert. Eine gemeinsam genutzte Methode macht die Instanzfelder nicht zu gemeinsam genutzten Feldern.

  6. 6
    ErklärungSpeichere Zustand hinter einem Setter

    Ein Thermostat kann target öffentlich zugänglich machen und #target privat speichern. Ein Getter liest den privaten Wert; ein Setter prüft eine angeforderte Änderung.

    Der Setter lehnt nicht endliche oder nicht numerische Eingaben und Werte außerhalb von 10 bis 30 °C ab, bevor er this.#target = value zuweist. Diese Reihenfolge ist wichtig: Wird vor der Zuweisung eine Ausnahme ausgelöst, bleibt der letzte gültige Sollwert erhalten. Der separate Speichername verhindert außerdem, dass der Setter sich wiederholt selbst aufruft.

  7. 7
    BeispielVerfolge eine akzeptierte und eine abgelehnte Änderung

    Beginne mit einem Thermostat-Sollwert von 20 °C. Die Zuweisung von 22 besteht beide Prüfungen, sodass der Setter 22 speichert. Die anschließende Zuweisung von 35 löst einen RangeError aus; der gespeicherte Wert bleibt 22.

    Number.isFinite(value) lehnt auch "22", NaN und Unendlichkeit ab. Die Bereichsvergleiche allein würden nicht jeden ungültigen Typ oder Wert ablehnen. Der private Speicher steuert den direkten Zugriff, während die Validierung steuert, was die öffentliche Schnittstelle akzeptiert.

  8. 8
    KernaussageWähle zwischen Klassen- und Instanzspeicher

    Ein mit static deklariertes Feld gehört zur Klasse. Lies die untere Schranke des Thermostats als Thermostat.MIN, während t.target den Zustand einer Instanz liest.

    Ein statischer Zähler kann erfassen, wie viele Objekte erstellt wurden. Ein normales Feld beginnt dagegen auf jedem neuen Objekt separat. Innerhalb einer statischen Methode ist this die Klasse, die den Aufruf empfängt, und stellt daher nicht den Sollwert oder die Maße einer einzelnen Instanz bereit.

  9. 9
    HerausforderungNutze den öffentlichen Zugriff

    Eine Unterklasse von Thermostat muss ihren Sollwert von 20 auf 24 °C erhöhen. Die Oberklasse deklariert #target und einen validierenden öffentlichen Setter target. Wie sollte die Unterklasse die Änderung anfordern und was würde ein direkter Zugriff über this.#target bewirken?

    ---reveal---

    Weise this.target = 24 zu, damit der geerbte Setter den Wert validiert und speichert. Die Unterklasse kann das private Feld der Oberklasse nicht direkt benennen; diese Verwendung von #target ist ein Syntaxfehler. Geerbte Zugriffsmethoden laufen weiterhin in der Klasse, die den privaten Zustand deklariert hat.

  10. 10
    BeispielGib verwandten Klassen eine Oberklasse

    Ein Konstruktor von Shape speichert einen Namen und seine Methode describe() ruft this.area() auf. Ein Kreis spezialisiert die Berechnung:

    class Circle extends Shape {
      constructor(radius) {
        super("Circle");
        this.radius = radius;
      }
      area() { return Math.PI * this.radius ** 2; }
    }
    

    super initialisiert den Teil der Oberklasse, bevor this.radius verwendet wird. Ein Kreis ist eine Form, daher passt die geerbte Beschreibung zu seiner Rolle.

  11. 11
    BeispielLass das Empfängerobjekt die Berechnung wählen

    Bei einem Radius von 2 cm gibt new Circle(2).describe() den Wert "Circle with area 12.57 cm²" zurück. Die Beschreibungsmethode ist geerbt, aber ihr Aufruf this.area() findet die überschreibende Methode des Kreises.

    Ein Rechteck kann dieselbe Beschreibung erben und die Multiplikation als eigene Flächenmethode bereitstellen. Eine Schleife, die describe() auf beiden Objekten aufruft, benötigt keine separaten Ausführungszweige für Kreis und Rechteck. Diese gemeinsame Schnittstelle mit unterschiedlichem Verhalten ist Polymorphie.

  12. 12
    ErklärungErweitere eine Methode der Oberklasse

    Ein Quadrat kann in seinem Konstruktor super(side, side) aufrufen, um einer Rechteck-Oberklasse gleiche Maße zu geben. Eine überschreibende Beschreibung kann dann super.describe() aufrufen und die Seitenlänge anhängen.

    super(...) im Konstruktor und super.describe() in einer Methode haben unterschiedliche Aufgaben: Das eine initialisiert die Oberklasse, das andere ruft eine Methode der Oberklasse auf. Eine Unterklasse ohne eigenen Konstruktor gibt Argumente automatisch weiter.

  13. 13
    HerausforderungWähle ein sinnvolles Modell

    Ein Report-Objekt muss Nachrichten über einen Notifier senden. Berichte sind keine Benachrichtigungsdienste. Wie sollten die Objekte miteinander verbunden sein und wie würde der Bericht eine Benachrichtigung anfordern?

    ---reveal---

    Verwende Komposition: Gib dem Bericht eine Eigenschaft für den Benachrichtigungsdienst und rufe dann eine Methode wie this.notifier.send(message) auf. Das ist eine „hat ein“-Beziehung. Wer Notifier erweitert, würde allein zur Wiederverwendung des Codes behaupten, dass jeder Bericht selbst ein Benachrichtigungsdienst ist. Das passt nicht zum Modell.

  14. 14
    ErklärungFinde eine Methode über die Kette

    Die eigenen Eigenschaften eines Kreises enthalten Daten wie seinen Radius. Fehlt ihm ein eigenes describe, durchsucht JavaScript zuerst Circle.prototype und dann Shape.prototype, wo die Methode gespeichert ist.

    Die gewöhnliche Kette führt weiter über Object.prototype bis zu null. Hat kein Objekt in der Kette eine angeforderte Eigenschaft, ergibt das Lesen undefined. instanceof Shape ist normalerweise erfolgreich, weil Shape.prototype in der Kette der Instanz vorkommt.

  15. 15
    BeispielVerdecke eine geerbte Einstellung

    Erstelle settings mit Object.create(defaults), wobei defaults.fontSize gleich 16 ist. Weise settings.fontSize = 18 zu.

    Die Zuweisung erstellt eine eigene Dateneigenschaft, die die geerbte verdeckt. Der Standardwert bleibt 16. Das Löschen von settings.fontSize entfernt die Verdeckung, sodass der nächste Lesezugriff wieder 16 auf dem Prototyp findet. Dieser Ablauf setzt eine gewöhnliche Dateneigenschaft voraus; stattdessen kann ein geerbter Setter eine Zuweisung behandeln.

  16. 16
    HerausforderungPrüfe eigene Eigenschaften getrennt vom Zugriff

    Ein Objekt panel erbt theme: "light" von einem einfachen Prototyp und hat kein eigenes theme. Was ergeben panel.theme, Object.hasOwn(panel, "theme") und "theme" in panel?

    ---reveal---

    Sie ergeben "light", false und true. Lesen und in können geerbte Eigenschaften finden, während Object.hasOwn nur danach fragt, was auf panel selbst gespeichert ist. Ein erfolgreicher Lesezugriff belegt nicht, dass es eine eigene Eigenschaft ist. Auch Object.keys(panel) lässt diesen geerbten Schlüssel weg.

  17. 17
    HerausforderungVerbinde Vererbung, privaten Zugriffsschutz und Suche

    Sensor deklariert #value, einen öffentlichen Getter value und eine Methode describe(), die this.value liest. IndoorSensor extends Sensor fügt keine Mitglieder hinzu. Warum kann ein Innensensor describe() aufrufen, obwohl sein Klassenrumpf #value nicht benennen kann?

    ---reveal---

    Die Suche findet die geerbte Methode, die mit dem Innensensor als this ausgeführt wird. Der in Sensor deklarierte Getter kann sein eigenes privates Feld auf dieser Instanz lesen. Die Vererbung stellt das öffentliche Verhalten bereit, ohne der Unterklasse direkten Zugriff auf den privaten Namen der Oberklasse zu gewähren.

  18. 18
    ZusammenfassungUntersuche ein Objekt in einer sinnvollen Reihenfolge

    Frag dich beim Verfolgen einer Klasseninstanz, wo ihre Daten gespeichert sind, welches Objekt den Methodenaufruf empfängt und wo die Suche die Methode findet. Läuft eine Änderung über einen Setter, verfolge die Validierung vor der Zuweisung.

    Untersuche bei einer unbekannten Hierarchie extends und die Konstruktorargumente, bevor du überschreibende Methoden verfolgst. Prüfe, welche Schlüssel dem Objekt selbst gehören, wenn du gespeicherte Schlüssel benötigst, und folge den Prototypen, wenn du geerbtes Verhalten erklären möchtest.

2

Verbinde ein Programm über Modulgrenzen hinweg

13 Schritte
Exportiere eine Klasse, lade sie in beiden Umgebungen und verschiebe optionale Arbeit auf später, ohne klare Abhängigkeiten zu verlieren.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungVerfolge einen Abhängigkeitsgraphen
  2. 2
    BeispielExportiere die Berechnung
  3. 3
    BeispielExportiere und nutze die Klasse
  4. 4
    HerausforderungLies einen geänderten Export
  5. 5
    BeispielStarte die Dateien in einem Browser
  6. 6
    ErklärungLöse einen Paketnamen auf
  7. 7
    HerausforderungWähle das Node.js-Ladesystem
  8. 8
    BeispielLade ein optionales Diagramm später
  9. 9
    KernaussageErmittle, was auf die Einrichtung wartet
  10. 10
    HerausforderungLöse einen unnötigen Zyklus auf
  11. 11
    TippHalte Arbeit aus Importen heraus
  12. 12
    HerausforderungVerbinde das Laden mit einer klaren Schnittstelle
  13. 13
    ZusammenfassungVerfolge einen Modulfehler nach Phasen
3

Stelle ein npm-Projekt auf einem anderen Computer wieder her

11 Schritte
Lies Skripte, wähle Abhängigkeitstypen und nutze Bereiche mit einer Lockdatei, um die Installation zu reproduzieren.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungMache das Projekt reproduzierbar
  2. 2
    BeispielErstelle die Paketbeschreibung
  3. 3
    BeispielLies die Aufgabe vor ihrer Ausführung
  4. 4
    HerausforderungBestimme eine Versionsänderung
  5. 5
    ErklärungHalte Code und Werkzeuge getrennt fest
  6. 6
    BeispielLies, was ein Bereich erlaubt
  7. 7
    ErklärungInstalliere den festgehaltenen Baum
  8. 8
    HerausforderungDeute eine gescheiterte saubere Installation
  9. 9
    TippPlane eine bewusste Aktualisierung
  10. 10
    HerausforderungVerbinde einen Bereich mit einem sauberen Build
  11. 11
    ZusammenfassungLies die beiden Paketeinträge zusammen
4

Prüfe ein Projekt von der Bearbeitung bis zum Build

15 Schritte
Nutze Linter-Prüfung, Formatierung, Produktionsvorschau und Tests, um unterschiedliche Arten von Fehlern zu untersuchen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungStelle jedem Werkzeug eine andere Frage
  2. 2
    ErklärungKonfiguriere einen hilfreichen Linter-Bericht
  3. 3
    BeispielFinde einen Tippfehler vor der Ausführung
  4. 4
    HerausforderungWähle eine Formatierungsprüfung
  5. 5
    BeispielFühre Entwicklung, Build und Vorschau aus
  6. 6
    BeispielVerfolge eine Buildoptimierung
  7. 7
    VerbindungVerbinde die Ausgabe mit dem Quellcode
  8. 8
    HerausforderungEntscheide, was neu gebaut werden muss
  9. 9
    BeispielSchreibe eine unabhängige Erwartung
  10. 10
    KernaussageVergleiche Inhalt und Identität richtig
  11. 11
    HerausforderungTeste den genauen Grenzwert
  12. 12
    TippWarte in einem asynchronen Test
  13. 13
    BeispielVerwende eine sinnvolle numerische Toleranz
  14. 14
    HerausforderungUntersuche einen erfolgreichen Build mit falschem Ergebnis
  15. 15
    ZusammenfassungLies Fehlschläge als Belege
5

Ordne Typen und Komponenten in ein funktionierendes Projekt ein

10 Schritte
Unterscheide Prüfung und Ausführung und entscheide dann, wie Projektwerkzeuge eine größere Benutzeroberfläche unterstützen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungFüge ein Werkzeug für einen bestimmten Bedarf hinzu
  2. 2
    BeispielErkenne einen unpassenden Aufruf
  3. 3
    ErklärungTrenne Transformation und Prüfung
  4. 4
    HerausforderungPrüfe Daten, die zur Laufzeit eintreffen
  5. 5
    ErklärungOrdne eine Komponente in den Arbeitsablauf ein
  6. 6
    BeispielLies das Aufgabenmenü des Projekts
  7. 7
    HerausforderungEntscheide, wann ein Framework hilft
  8. 8
    HerausforderungFinde die fehlende Prüfung
  9. 9
    TippFühre Prüfungen schrittweise ein
  10. 10
    ZusammenfassungVerfolge, welche Belege jedes Werkzeug liefert

Klassen und Module in JavaScript: Übungsaufgaben

50 Übungsfragen in 5 Sets

Set 1: Lies Klassen, Importe und Projektaufgaben10 Übungsfragen

Frage 1 von 10

Ein Modul exportiert eine Funktion als Standardexport und außerdem LIMIT als benannten Export. Wie kann eine Deklaration die Funktion als calculate und die Konstante unter ihrem exportierten Namen importieren?
  1. import { calculate, LIMIT } from "./calc.js";
  2. import calculate, LIMIT from "./calc.js";
  3. import calculate, { LIMIT } from "./calc.js";
  4. import { default, LIMIT } from "./calc.js";
Antwort zeigenAntwort ausblenden
Antwort: C
Die Standardbindung steht ohne geschweifte Klammern, gefolgt vom benannten Import in geschweiften Klammern. Die Anforderung { calculate, LIMIT } fragt nach zwei benannten Exporten, aber die Funktion wurde als Standardexport bereitgestellt. Der lokale Name calculate wird vom Importeur gewählt und muss nicht mit dem Deklarationsnamen der Funktion übereinstimmen.

Frage 2 von 10

Eine Klasse deklariert static created = 8;. Ihre Instanz wird batch zugewiesen und die Klasse heißt Batch. Wie wird der gespeicherte Zählerstand gelesen?
  1. Batch.created
  2. new Batch().created
  3. Batch.prototype.created
  4. batch.constructor.prototype.created
Antwort zeigenAntwort ausblenden
Antwort: A
Ein statisches Feld gehört zur Klasse, daher wird der Zählerstand als Batch.created gelesen. Der Zugriff auf batch.created durchsucht die Instanz und ihre Prototypenkette, auf der dieses statische Feld nicht abgelegt wurde. Statisch bedeutet nicht, dass ein Feld auf jedes Objekt kopiert wird.

Frage 3 von 10

Warum schlägt dieser Konstruktor fehl und welche Reihenfolge behebt das Problem?

class Item {
  constructor(code) { this.code = code; }
}
class Box extends Item {
  constructor(code) {
    this.open = false;
    super(code);
  }
}
new Box("K7");
  1. Ein eigenes Feld code fehlt; weise zuerst this.code zu.
  2. Er erbt einen Konstruktor; entferne den Aufruf super(code).
  3. Er übergibt eine Zeichenkette; wandle zuerst code um.
  4. Er nutzt this zu früh; rufe zuerst super(code) auf.
Antwort zeigenAntwort ausblenden
Antwort: D
Ein Konstruktor einer abgeleiteten Klasse kann this erst verwenden, nachdem der Konstruktor der Oberklasse die Instanz über super(code) initialisiert hat. Verschiebe diesen Aufruf vor die Zuweisung an open. Einem anderen Feld zuerst einen Wert zuzuweisen, hätte dasselbe Problem, weil weiterhin zu früh auf this zugegriffen würde.

Frage 4 von 10

Ein Modul enthält nur export default class Badge {}. Welcher Import bindet diese Klasse an den lokalen Namen Tag?
  1. import { Tag } from "./badge.js";
  2. import Tag from "./badge.js";
  3. import { Badge as Tag } from "./badge.js";
  4. import * as Tag from "./badge.js";
Antwort zeigenAntwort ausblenden
Antwort: B
Ein Standardimport verwendet keine geschweiften Klammern und kann den lokalen Namen Tag wählen. Der Import von { Badge as Tag } fordert dagegen einen benannten Export namens Badge an, den dieses Modul nicht bereitstellt. Ein Namensraumimport würde ein Objekt binden, das den Standardexport enthält, nicht die Klasse selbst.

Frage 5 von 10

Eine Browser-Einstiegsdatei enthält eine import-Deklaration, aber ihr script-Tag hat kein type-Attribut. Welche HTML-Änderung macht sie zu einem ES-Modul?
  1. Füge nur defer zum script-Tag hinzu.
  2. Füge nur async zum script-Tag hinzu.
  3. Füge type="module" zum script-Tag hinzu.
  4. Füge type="text/javascript" zum script-Tag hinzu.
Antwort zeigenAntwort ausblenden
Antwort: C
type="module" weist den Browser an, ES-Modulsyntax und die zugehörigen Laderegeln zu verwenden. Nur defer hinzuzufügen, ändert den Ausführungszeitpunkt eines klassischen Skripts, macht Importdeklarationen darin aber nicht gültig. Das Einstiegsmodul kann seine Abhängigkeiten dann automatisch laden, wenn die Dateien korrekt bereitgestellt werden.

Frage 6 von 10

Ein Projekt enthält "scripts": { "check": "eslint ." }. Welcher Befehl führt diese benannte Aufgabe aus?
  1. npm check
  2. npm install check
  3. node check
  4. npm run check
Antwort zeigenAntwort ausblenden
Antwort: D
Gewöhnliche eigene Skriptnamen werden mit npm run ausgeführt, diese Aufgabe also mit npm run check. npm check wird nicht zur Kurzform, nur weil ein Skript so heißt; die bekannten Formen npm test und npm start sind Sonderfälle. Das Skript führt den festgelegten ESLint-Befehl aus.

Frage 7 von 10

Ein Projekt verwendet einen Codeformatierer nur während der Entwicklung. In welchem Abschnitt von package.json sollte sein direkter Paketeintrag normalerweise stehen?
  1. devDependencies
  2. dependencies
  3. scripts
  4. engines
Antwort zeigenAntwort ausblenden
Antwort: A
Ein Codeformatierer ist ein Entwicklungswerkzeug, daher gehört sein Paket in devDependencies und wird normalerweise mit npm install -D hinzugefügt. Der Skriptabschnitt kann einen Befehl enthalten, der ihn ausführt, hält damit aber nicht die Paketabhängigkeit fest. Bibliothekscode für die Laufzeit gehört in dependencies.

Frage 8 von 10

Ein ESLint-Durchlauf meldet bei den üblichen Einstellungen für den Rückgabestatus eine Warnung und keine Fehler. Was belegt ein erfolgreicher Abschluss über den Code?
  1. Keine Linter-Regel wurde ausgelöst; die Warnung betrifft nur Formatierung.
  2. Jedes Verhalten ist korrekt; die Warnung kann die Ausführung nicht beeinflussen.
  3. Keine Regel auf Fehlerstufe schlug fehl; die Warnung muss noch geprüft werden.
  4. Die Warnung wurde behoben; erfolgreiche Linter-Prüfungen ändern immer Dateien.
Antwort zeigenAntwort ausblenden
Antwort: C
Warnungen werden standardmäßig gemeldet, ohne ESLint fehlschlagen zu lassen, sodass ein erfolgreicher Abschluss trotz Warnung möglich ist. Er belegt kein korrektes Verhalten: Die Linter-Prüfung liest konfigurierte Muster, ohne das Programm auszuführen. Automatische Änderungen benötigen einen Korrekturbefehl und ein Problem, für das eine Korrektur existiert.

Frage 9 von 10

Eine Funktion gibt ein neu erstelltes Array mit "a" und "b" zurück. Wie sollte ein Vitest-Test diesen Inhalt mit einem separaten Arrayliteral vergleichen?
  1. expect(result).toBe(["a", "b"]);
  2. expect(result).toEqual(["a", "b"]);
  3. expect(result === ["a", "b"]).toBe(true);
  4. expect(Object.is(result, ["a", "b"])).toBe(true);
Antwort zeigenAntwort ausblenden
Antwort: B
toEqual prüft den Inhalt des Arrays einschließlich der Reihenfolge seiner Werte. toBe und die Identitätsausdrücke vergleichen, ob beide Operanden dasselbe Objekt sind; ein separates Arrayliteral erstellt ein anderes Objekt. Gleicher Inhalt erfordert daher den gezeigten tiefen Vergleich.

Frage 10 von 10

Eine Funktion, die für die Entgegennahme von Zahlen deklariert ist, erhält geparste Serverdaten. Ein Vite-Build ist erfolgreich, aber das laufende Programm hängt eine Zeichenkette an, wo eine Summe vorgesehen war. Das Projekt hat weder eine separate Typprüfungsaufgabe noch eine Laufzeitprüfung der Daten. Welche Änderungen prüfen beide ungeprüften Grenzen?
  1. Eine Typprüfung ausführen und geparste Werte vor der Berechnung validieren.
  2. Den Codeformatierer ausführen und geparste Daten als numerisch deklarieren.
  3. Eine Typprüfung ausführen und jeder typisierten Serverantwort vertrauen.
  4. Eine Produktionsvorschau ausführen und die Typannotationen entfernen.
Antwort zeigenAntwort ausblenden
Antwort: A
Vite kann Typen entfernen, ohne sie zu prüfen. Eine separate Typprüfung behandelt daher Typfehler im Quellcode. Der tatsächliche Serverwert benötigt weiterhin eine Laufzeitvalidierung, weil Deklarationen eingehende Daten nicht untersuchen. Eine Typprüfung allein kann nicht beweisen, dass die Antwort ihrer deklarierten Struktur entspricht.
Set 2: Wende Module und reproduzierbare Projekteinstellungen an10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was geschieht in der letzten Zeile?

class Meter {
  value = 2;
  read() { return this.value; }
}
const meter = new Meter();
const read = meter.read;
read();
  1. Sie gibt 2 zurück, weil die Zuweisung einer Methode ihr Empfängerobjekt erhält.
  2. Sie löst eine Ausnahme aus, weil beim losgelösten Aufruf this gleich undefined ist.
  3. Sie gibt undefined zurück, weil das Klassenfeld privat ist.
  4. Sie löst eine Ausnahme aus, weil Instanzmethoden keinen Variablen zugewiesen werden können.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was ist das letzte Ergebnis?

const base = { unit: "cm" };
const sample = Object.create(base);
Object.hasOwn(sample, "unit");
  1. true
  2. "cm"
  3. undefined
  4. false
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Was gibt der letzte Ausdruck zurück?

class Label {
  constructor(text) { this.text = text; }
  length() { return this.text.length; }
}
new Label("Orbit").length();
  1. 5
  2. 4
  3. undefined
  4. "Orbit"
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Was gibt import("./help.js") unmittelbar zurück?
  1. Den als Standard exportierten Wert des Moduls selbst.
  2. Einen neuen Namensraum mit synchroner Auswertung.
  3. Ein Promise für das Modulnamensraumobjekt.
  4. Ein Array mit allen exportierten Werten.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein stabiles Paket der Version 7.3.6 veröffentlicht eine kompatible Fehlerkorrektur ohne neue Funktion. Welche nächste Version entspricht der semantischen Versionierung?
  1. 7.4.0
  2. 7.3.7
  3. 8.0.0
  4. 7.3.6
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Projekt erlaubt ~6.4.2. Welche ist die neueste erlaubte stabile Version unter 6.4.9, 6.5.0, 7.0.0 und 6.4.1?
  1. 6.4.9
  2. 6.5.0
  3. 7.0.0
  4. 6.4.1
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Welche Aufgabe schreibt in einem Vite-Projekt die optimierten Produktionsdateien in den üblichen Ausgabeordner?
  1. npm run dev
  2. npm run preview
  3. npm install
  4. npm run build
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Test ruft ein asynchrones loadItems() auf, ohne darauf zu warten. Der Test-Callback endet; das Promise wird später mit einem neuen Array erfüllt. Die vorgesehene Assertion verwendet toBe(["x"]). Was muss sich ändern, damit der Test den versprochenen Inhalt zuverlässig prüft?
  1. Den Test sofort beenden und toEqual(["x"]) verwenden.
  2. In einem asynchronen Test auf loadItems() warten und toBe(["x"]) beibehalten.
  3. In einem asynchronen Test auf loadItems() warten und toEqual(["x"]) verwenden.
  4. Den Aufruf ohne Warten beibehalten und das Promise mit toBe(["x"]) prüfen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein .ts-Programm läuft in Node.js durch unterstütztes Type Stripping. Warum belegt dieser erfolgreiche Lauf nicht, dass alle deklarierten Typen korrekt sind?
  1. Node.js wandelt jeden eingehenden Wert in seinen deklarierten Typ um.
  2. Typannotationen bleiben nur bis zum ersten Funktionsaufruf aktiv.
  3. Type Stripping entfernt Syntax, ohne eine Typprüfung durchzuführen.
  4. Node.js prüft Typen nur für Code, der Browser-APIs verwendet.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Team installiert ein Komponenten-Framework, ESLint und einen Testrunner in einer Vite-Vorlage. Es gibt nur die ursprünglichen Entwicklungs- und Buildskripte; eine Linter-Konfiguration und Testcode fehlen. Welche Arbeit ist noch nötig, um wiederholbare Linter- und Verhaltensprüfungen zu ermöglichen?
  1. Die Werkzeuge global neu installieren und das vorhandene Buildskript nutzen.
  2. Die Linter-Prüfung konfigurieren, Assertions schreiben und Prüfungen als Skripte anbieten.
  3. Nur Skriptnamen hinzufügen und die Pakete das Verhalten ableiten lassen.
  4. Die Werkzeuge zu Laufzeitabhängigkeiten machen und die Vorlage neu bauen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Verfolge Zustand, Abhängigkeiten und Buildverhalten10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein Setter akzeptiert nur endliche Zahlen von 4 bis einschließlich 9. Seine Instanz speichert 6. Der Setter prüft die Eingabe vor der Zuweisung und löst bei einem Fehler eine Ausnahme aus. Welcher Wert bleibt nach einem abgefangenen Versuch, "8" zuzuweisen, erhalten und warum?
  1. 8 bleibt erhalten, weil die Bereichsprüfung die Zeichenkette umwandelt.
  2. 6 bleibt erhalten, weil private Felder jeden Setter-Aufruf ablehnen.
  3. 9 bleibt erhalten, weil der Setter ungültige Werte auf das Maximum begrenzt.
  4. 6 bleibt erhalten, weil die Zeichenkette die Prüfung auf eine endliche Zahl nicht besteht.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was sind die abschließend gelesenen Werte?

const base = { value: 4, read() { return this.value; } };
const x = Object.create(base);
const y = Object.create(x);
x.value = 7;
y.value = 10;
delete y.value;
[y.read(), Object.hasOwn(y, "read"), base.value];
  1. [4, false, 4]
  2. [7, false, 4]
  3. [7, true, 7]
  4. [10, false, 4]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Was sind die letzten beiden Werte?

const defaults = { size: 11 };
const item = Object.create(defaults);
item.size = 15;
delete item.size;
[item.size, defaults.size];
  1. [undefined, 11]
  2. [15, 15]
  3. [11, 11]
  4. [undefined, undefined]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein einfaches Browsermodul importiert "tiny-calendar". Das Paket ist lokal installiert, aber der Browser meldet einen nicht aufgelösten Modulbezeichner. Welche fehlende Einrichtung erklärt das?
  1. Eine Zuordnung oder ein Werkzeug, das den bloßen Namen zu browserladbarem Code auflöst.
  2. Eine zweite Installation, die das Paket in globale Variablen kopiert.
  3. Eine CommonJS-Typeinstellung, durch die der Browser node_modules durchsucht.
  4. Ein async-Attribut, das die Auflösung des bloßen Namens bis nach dem Parsen verzögert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

main.js importiert statisch config.js, das auf eine Netzwerkantwort wartet, bevor es Einstellungen exportiert. Ein unabhängiger Einstieg clock.js importiert keine der beiden Dateien. Später führt der asynchrone Handler von main const plugin = await import("./plugin.js") aus; dessen einziger Export ist die Standardklasse Plugin. Was beschreibt das Warten und die Konstruktion korrekt?
  1. Beide Einstiege warten auf die Konfiguration; Konstruktion mit new plugin.default().
  2. Main wartet; clock kann fortfahren; Konstruktion mit new plugin().
  3. Keiner wartet auf die Konfiguration; Konstruktion mit new plugin.Plugin().
  4. Main wartet; clock kann fortfahren; Konstruktion mit new plugin.default().
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Übereinstimmende Paketdateien deklarieren ^8.1.0 und legen eine Abhängigkeit auf 8.1.3 fest. Ein sauberer Build führt npm ci aus, nachdem 8.7.0 veröffentlicht wurde. Welche Version wird installiert?
  1. 8.7.0
  2. 8.1.0
  3. 8.1.3
  4. Die neueste 9.x-Version.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ein Entwickler muss die vorhandene Vite-Produktionsausgabe über einen lokalen HTTP-Server untersuchen. Welche Projektaufgabe erledigt das normalerweise?
  1. npm run dev
  2. npm run preview
  3. npm run build
  4. npm init -y
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Einstieg importiert eine reine Hilfsfunktion aus einem Modul, das zwei Hilfsfunktionen exportiert und außerdem eine erforderliche Registrierung auf oberster Ebene ausführt. Ein Vite-Produktionsbuild minifiziert die Ausgabe und enthält eine bei Bedarf geladene Funktion. Welche Aussage über die Ausgabe ist gerechtfertigt?
  1. Ungenutzter Hilfscode kann entfernt, die Registrierung erhalten und später geladener Code aufgeteilt werden.
  2. Aller nicht importierte Code samt Registrierung muss in einer sofort geladenen Datei verschwinden.
  3. Beide Hilfsfunktionen müssen bleiben, die Registrierung entfällt und später geladener Code wird eingebettet.
  4. Jede Quelldatei muss eine Ausgabedatei mit allen ursprünglichen Namen werden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Welcher Befehl prüft ein TypeScript-Projekt, ohne ausgegebenes JavaScript zu schreiben?
  1. vite build
  2. node app.ts
  3. prettier . --check
  4. tsc --noEmit
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine Anwendung ruft bei Bedarf eine Funktion zur Datumsformatierung auf. Ein System für Benutzeroberflächen ruft dagegen den Komponentencode der Anwendung auf, wenn Rendern erforderlich ist. Welchen Unterschied veranschaulichen diese Beispiele?
  1. Eine Bibliothek liefert aufrufbare Hilfsfunktionen; ein Framework koordiniert Aufrufe von Anwendungscode.
  2. Ein Framework liefert aufrufbare Hilfsfunktionen; eine Bibliothek koordiniert das gesamte Rendern der Anwendung.
  3. Eine Bibliothek ersetzt Module; ein Framework ersetzt Paketinstallation und Builds.
  4. Ein Framework prüft Laufzeittypen; eine Bibliothek prüft Typen nur während der Entwicklung.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Diagnostiziere Klassen- und Projektfehler10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was sind die abschließend gelesenen Werte?

class Counter {
  count = 1;
  add() { this.count += 2; }
}
const a = new Counter();
const b = new Counter();
const addA = a.add.bind(a);
b.count = 10;
addA();
const callB = () => b.add();
callB();
[a.count, b.count];
  1. [3, 12]
  2. [1, 14]
  3. [12, 12]
  4. [3, 10]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine Klasse speichert ihren einzigen Zustand im privaten Feld #level und stellt auf ihrem Prototyp einen öffentlichen Getter bereit. Sie definiert keine Methode toJSON. Was ergibt JSON.stringify(new Gauge())?
  1. "{\"level\":0}"
  2. "{\"#level\":0}"
  3. "{}"
  4. undefined
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

class Photo extends Asset {} wird ohne Konstruktor deklariert. Asset speichert das Argument, das an seinen Konstruktor übergeben wird. Was geschieht mit einem Argument in new Photo("P8")?
  1. Es wird verworfen, weil der Unterklassenkonstruktor fehlt.
  2. Der Standardkonstruktor der Unterklasse gibt es an Asset weiter.
  3. Es wird zu einem statischen Feld auf der Klasse Photo.
  4. Es wird nur gespeichert, wenn Photo jede geerbte Methode überschreibt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein Modul exportiert let count = 1, ein Objekt state = { count: 1 } und advance(), das beide Zähler erhöht. Zwei weitere Module importieren dieselben Exporte. Das erste ruft advance() auf und weist dann state.count = 9 zu. Was liest das zweite als [count, state.count] und kann es count einen neuen Wert zuweisen?
  1. Es liest [1, 1] und kann seiner privaten importierten Kopie einen neuen Wert zuweisen.
  2. Es liest [2, 2] und kann beiden importierten Bindungen neue Werte zuweisen.
  3. Es liest [1, 9] und kann Änderungen an exportierten primitiven Werten nicht sehen.
  4. Es liest [2, 9] und kann dem importierten count keinen neuen Wert zuweisen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein Modul deklariert save() und eine Schaltfläche verwendet inline onclick="save()". Das Modul lädt korrekt, aber beim Klicken wird gemeldet, dass save undefiniert ist. Wie sollte das Ereignis verbunden werden?
  1. defer hinzufügen und den Inline-Handler unverändert lassen.
  2. save aus dem Modul mit addEventListener registrieren.
  3. save exportieren und erwarten, dass HTML den Namen automatisch importiert.
  4. Die Datei in .mjs umbenennen und den Inline-Handler beibehalten.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Die Skripte eines Projekts enthalten "inspect": "eslint src". Welcher Befehl führt dieses Skript mit dem ESLint-Argument --fix aus?
  1. npm run inspect -- --fix
  2. npm run inspect --fix
  3. npm install inspect -- --fix
  4. npm inspect src --fix
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine gemeinsam genutzte ESLint-Konfiguration erzwingt einen zu Prettier entgegengesetzten Stil für Anführungszeichen. In gespeicherten Dateien wechseln die Anführungszeichen wiederholt hin und her. Der Code gibt außerdem einen undefinierten Namen zurück, der no-undef auslöst. Welche Einrichtung beseitigt den Formatierungskonflikt und erhält die nützliche Fehlerprüfung?
  1. Stilregeln und no-undef deaktivieren, dann einen Codeformatierer verwenden.
  2. Widersprüchliche Stilregeln und no-undef behalten, dann einen Codeformatierer verwenden.
  3. Widersprüchliche Stilregeln deaktivieren, no-undef behalten und einen Codeformatierer verwenden.
  4. Stilregeln deaktivieren, no-undef behalten und konkurrierende Codeformatierer weiterverwenden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Welche Art von Problem ändert der Prettier-Befehl --write direkt?
  1. Die in Verhaltens-Assertions gespeicherten erwarteten Ergebnisse.
  2. Die aus Laufzeitdaten abgeleiteten falschen Variablennamen.
  3. Die durch Abhängigkeitsbereiche erlaubten veröffentlichten Versionen.
  4. Abstände und Layout in unterstützten Quelldateien.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine Prüfung muss endliche numerische Längen von 0 bis einschließlich 12 cm akzeptieren. Welche drei Testerwartungen decken unterschiedliche Fehler in dieser Implementierung auf?

function setLength(n) {
  if (n <= 0 || n > 12) throw new RangeError();
  return n;
}
  1. 0 akzeptieren; "7" ablehnen; NaN ablehnen.
  2. 12 akzeptieren; "7" ablehnen; NaN ablehnen.
  3. 0 akzeptieren; "7" akzeptieren; NaN ablehnen.
  4. 0 akzeptieren; "7" ablehnen; NaN akzeptieren.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine statische Website verwendet npm-Werkzeuge, um Browserausgaben zu bauen. Welche Rolle hat der Ordner dist in diesem Arbeitsablauf?
  1. Quellkonfiguration, die vor jedem Build bearbeitet werden muss.
  2. Der genaue Abhängigkeitseintrag, der die npm-Lockdatei ersetzt.
  3. Generierte Ausgabe, die ein geeigneter statischer Hoster bereitstellen kann.
  4. Installierte Entwicklungswerkzeuge, die jeder Browser separat herunterlädt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 5: Kombiniere die Konzepte in unbekannten Projekten10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was gibt new LoudNote("A").describe() zurück?

class Note {
  constructor(text) { this.text = text; }
  label() { return this.text; }
  describe() { return "[" + this.label() + "]"; }
}
class LoudNote extends Note {
  label() { return super.label() + "!"; }
  describe() { return super.describe() + "?"; }
}
  1. "[A]!?"
  2. "[A]?"
  3. "[A!]?"
  4. "[A!?]"
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was gibt der letzte Aufruf zurück?

class Base {
  constructor(n) { this.n = n; }
  value() { return this.n; }
  report() { return this.value() + 1; }
}
class Double extends Base {
  value() { return super.value() * 2; }
}
class Extra extends Double {
  report() { return super.report() + 3; }
}
new Extra(4).report();
  1. 8
  2. 9
  3. 16
  4. 12
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

feature.js hat einen Standardexport und das benannte ready. Eine Barrel-Datei enthält nur export * from "./feature.js";. Was leitet die Barrel-Datei weiter?
  1. Beide Exporte, wobei der Standardexport in feature umbenannt wird.
  2. Den benannten Export ready, ohne den Standardexport weiterzuleiten.
  3. Nur den Standardexport, während benannte Exporte privat bleiben.
  4. Keinen der Exporte, weil eine Barrel-Datei sie durch Funktionsaufrufe auswerten muss.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein Datenmodul importiert auf oberster Ebene ein Modul für die Benutzeroberfläche, um sofort zu rendern. Die Benutzeroberfläche importiert das Datenmodul und liest eine nicht initialisierte Bindung. Unittests, die die Daten importieren, versuchen außerdem, in Node.js auf document zuzugreifen. Welche Umstrukturierung behebt beide Fehler?
  1. Ereignisverknüpfungen ins Einstiegsmodul verschieben und gemeinsame Datenlogik unabhängig von der Oberfläche halten.
  2. Dieselben zyklischen Importe mit einem Timer verzögern und einen globalen document-Namen hinzufügen.
  3. Alle gemeinsamen Definitionen in eine größere Barrel-Datei legen und das Rendern beim Import beibehalten.
  4. Jeden Importfehler abfangen und das unveränderte Oberflächenmodul bis zur Initialisierung erneut ausführen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Was verhindert "private": true in package.json direkt?
  1. Dass andere Module die exportierten Funktionen importieren.
  2. Dass Browsernutzer die gebauten Quelldateien lesen.
  3. Dass das Paket versehentlich über npm veröffentlicht wird.
  4. Dass npm die Entwicklungsabhängigkeiten des Projekts installiert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Projekt deklariert ^0.6.2, legt 0.6.4 fest und hat eine gültige passende Lockdatei. Die Registry bietet 0.6.9 und 0.7.0 an. Welche Folge beschreibt die Version nach npm ci und danach die neueste erlaubte Version nach einem bewussten npm update?
  1. Zuerst 0.6.9, dann 0.7.0.
  2. Zuerst 0.6.4, dann 0.6.9.
  3. Zuerst 0.6.4, dann 0.7.0.
  4. Zuerst 0.6.2, dann 0.6.4.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Frontend-Quelldatei liest eine Zugangsinformation aus einer benutzerdefinierten VITE_-Variablen. Warum ist diese Zugangsinformation selbst nach der Minifizierung für diesen Ort ungeeignet?
  1. Die Variable existiert nur im Editor und verschwindet vor dem Build.
  2. Das Präfix verschlüsselt den Wert nur im aktiven Entwicklungsmodus.
  3. Der Wert ist geschützt, sofern nicht auch eine Source Map veröffentlicht wird.
  4. Der offengelegte Wert wird an Browsernutzer ausgeliefert und kann untersucht werden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Funktion soll einen leeren Namen ablehnen, indem sie RangeError auslöst. Welche Vitest-Assertion ermöglicht der Vergleichsmethode, die Ausnahme zu erfassen?
  1. expect(() => createName("")).toThrow(RangeError);
  2. expect(createName("")).toThrow(RangeError);
  3. expect(() => createName("")).toBe(RangeError);
  4. expect(createName).toEqual(new RangeError());
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine Klasse verwendet TypeScript-private value, weist ihm geparste Netzwerkeingaben zu und gibt mit der falschen Formel ein numerisches Ergebnis zurück. Das Projekt besteht tsc --noEmit. Welche Kombination behandelt privaten Zugriffsschutz zur Laufzeit, externe Eingaben und Verhalten?
  1. Das private-Schlüsselwort behalten, den Antworttyp zusichern und die Formel in Tests wiederholen.
  2. Ein JavaScript-#-Feld nutzen, Eingaben validieren und unabhängige erwartete Ergebnisse testen.
  3. Ein JavaScript-#-Feld nutzen, der Antwortannotation vertrauen und Formatierung ausführen.
  4. Eingaben validieren, die Prüfung mit any deaktivieren und einem erfolgreichen Build vertrauen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Komponentenprojekt wird erfolgreich gebaut, benötigt aber koordinierte Seiten-URLs und anfängliches, auf dem Server gerendertes HTML. Welche übergeordnete Projektebene stellt üblicherweise beide Funktionen rund um die Komponentenoberfläche bereit?
  1. Ein clientseitiger Router, der erst nach dem Laden von JavaScript läuft.
  2. Eine statische Rückfallseite ohne einen Rendern-Schritt auf dem Server.
  3. Ein Komponentenzustandsspeicher ohne Routing-Integration.
  4. Ein Meta-Framework mit Routing und Rendern auf dem Server.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

88 Schlüsselbegriffe, jeweils mit Definition

A

Abhängigkeit
Eine Abhängigkeit ist ein Paket, auf das das Projekt angewiesen ist; Laufzeitpakete werden normalerweise im Abschnitt dependencies von package.json festgehalten.
Eine von der Anwendung aufgerufene Datumsformatierungsbibliothek ist eine Laufzeitabhängigkeit, selbst wenn sie für den Browser gebündelt wird.
Arrange–Act–Assert
Arrange–Act–Assert ist eine Teststruktur, die Eingaben vorbereitet, das Verhalten ausführt und das Ergebnis anhand einer Erwartung prüft.
Ein Test erstellt ein Rechteck, ruft seine Flächenmethode auf und prüft anschließend ein unabhängig berechnetes Ergebnis.
Assertion
Eine Assertion ist eine Testanweisung, die eine bestimmte erwartete Eigenschaft eines Ergebnisses prüft und einen Fehler meldet, wenn die Erwartung nicht erfüllt wird.
Eine Assertion kann prüfen, ob eine ungültige Seitenlänge eine Ausnahme auslöst, statt ein nutzbares Rechteck zu erstellen.
Aufzählbare Eigenschaft
Eine aufzählbare Eigenschaft besitzt ein Flag, durch das sie bei Aufzählungsoperationen erscheinen kann, die aufzählbare Schlüssel auswählen.
Object.keys listet eigene aufzählbare Zeichenkettenschlüssel auf, während for...in auch geerbte Schlüssel einbeziehen kann.

B

Barrel-Datei
Eine Barrel-Datei sammelt Reexporte mehrerer Module an einer Importstelle und macht deren gemeinsame Schnittstelle leichter erreichbar.
Eine große Barrel-Datei kann eine zyklische Abhängigkeit verbergen, wenn ein Modul über die Indexdatei seines eigenen Ordners importiert.
Benannter Export
Ein benannter Export stellt eine Deklaration unter einem bestimmten exportierten Namen bereit, den Importeure in einer Importdeklaration mit geschweiften Klammern anfordern.
Ein Modul für Schranken exportiert MAX, und ein Importeur kann den Namen direkt anfordern oder lokal umbenennen.
Bibliothek
Eine Bibliothek stellt wiederverwendbaren Code bereit, den Anwendungscode bei Bedarf aufruft, wobei das aufrufende Programm die Kontrolle über diese Aufrufe behält.
Eine Anwendung ruft eine Hilfsfunktion zur Datumsformatierung auf, wenn sie einen Zeitstempel in der Oberfläche anzeigen muss.
Bloßer Modulbezeichner
Ein bloßer Modulbezeichner nennt ein Paket ohne Pfadpräfix oder vollständige URL, sodass die Umgebung oder Werkzeuge diesen Namen auflösen müssen.
Node.js kann einen installierten Paketnamen auflösen, den ein einfacher Browser ohne zusätzliche Zuordnung nicht finden kann.
Bundler
Ein Bundler folgt den Abhängigkeiten eines Programms und fasst sie zu Ausgabedateien zusammen oder transformiert sie, damit sie Nutzern bereitgestellt werden können.
Ein Browserbuild kann installierte Pakete auflösen und optimierte Dateien in den generierten Ordner dist schreiben.

C

Code-Splitting
Code-Splitting teilt gebauten Code in separat ladbare Abschnitte, sodass manche Funktionen später statt beim ersten Start abgerufen werden können.
Ein dynamischer Import für einen selten verwendeten Editor kann einem Buildwerkzeug eine Grenze für das spätere Laden geben.
Codeformatierer
Ein Codeformatierer gestaltet das Codelayout einheitlich um und ordnet Leerzeichen, Zeilenumbrüche, Einrückung und andere unterstützte Stilelemente an.
Prettier kann Abstände in einem Objekt vereinheitlichen, ohne zu entscheiden, ob das Objekt die richtigen Werte enthält.
CommonJS
CommonJS ist das ursprüngliche Modulsystem von Node.js und verwendet synchrone require-Aufrufe und module.exports, um Werte bereitzustellen.
Eine .cjs-Datei bleibt CommonJS, selbst wenn das umgebende Paket ausdrücklich ES-Module auswählt.

D

Dynamischer Import
Ein dynamischer Import ist ein import()-Ausdruck, der ein Modul bei Bedarf lädt und ein Promise für seinen Modulnamensraum zurückgibt.
Ein asynchroner Schaltflächen-Handler kann ein optionales Diagramm erst laden, wenn der Nutzer dessen Anzeige anfordert.

E

Eigene Eigenschaft
Eine eigene Eigenschaft wird direkt auf einem Objekt gespeichert, anders als eine geerbte Eigenschaft, die über eine seiner Prototypverknüpfungen verfügbar ist.
Die Breite eines Rechtecks kann eine eigene Eigenschaft sein, obwohl seine gewöhnliche Flächenmethode geerbt ist.
Empfängerobjekt
Ein Empfängerobjekt ist das Objekt, auf dem eine Methode aufgerufen wird und das bei einem gewöhnlichen Methodenaufruf normalerweise den Wert von this liefert.
In box.open() ist box das Empfängerobjekt; das Loslösen von open bindet dieses Empfängerobjekt nicht dauerhaft.
Entwicklungsabhängigkeit
Eine Entwicklungsabhängigkeit ist ein Paket, das zum Entwickeln, Prüfen oder Bauen eines Projekts benötigt wird und nicht als dessen Bibliothekscode zur Laufzeit dient.
Ein Codeformatierer oder Testrunner wird üblicherweise mit -D installiert, damit seine Version für das Projekt festgehalten wird.
Entwicklungsserver
Ein Entwicklungsserver stellt ein Projekt während der Bearbeitung lokal bereit und kann Importe auflösen, Quellcode transformieren und die Seite bei Dateiänderungen aktualisieren.
Ein Vite-Entwicklungsserver gibt eine lokale HTTP-Adresse aus, über die der Browser die in Arbeit befindliche Anwendung lädt.
ES-Modul
Ein ES-Modul ist ein JavaScript-Modul, das die Standard-Syntax mit import und export verwendet und einen eigenen Gültigkeitsbereich sowie strikte Ausführungsregeln hat.
Ein Formenmodul kann Geometriehilfsfunktionen importieren, ohne deren Namen im globalen Gültigkeitsbereich der Seite abzulegen.

F

Flache Konfiguration
Die flache Konfiguration ist das aktuelle JavaScript-basierte Konfigurationsformat von ESLint, das Konfigurationsobjekte und Regeleinstellungen kombiniert.
Ein Modul eslint.config.js kann empfohlene Prüfungen sowie die im Browsercode verfügbaren globalen Namen exportieren.
Framework
Ein Framework stellt eine Anwendungsstruktur bereit und koordiniert, wann innerhalb dieser Struktur vom Nutzer bereitgestellter Code ausgeführt wird.
Ein Framework für Benutzeroberflächen kann Komponentencode aufrufen, wenn eine Zustandsänderung eine Aktualisierung der angezeigten Oberfläche erfordert.

G

Geerbte Eigenschaft
Eine geerbte Eigenschaft wird über die Prototypenkette eines Objekts gefunden, statt als eigene Eigenschaft auf diesem Objekt gespeichert zu sein.
Ein Einstellungsobjekt kann ein Standarddesign lesen, während Object.hasOwn meldet, dass es keinen eigenen Designschlüssel hat.
Getter
Ein Getter ist eine Zugriffsmethode, die beim Lesen einer Eigenschaft ausgeführt wird und es ermöglicht, einen Wert ohne Aufrufklammern zu berechnen oder zugänglich zu machen.
Das Lesen von thermostat.target kann einen Getter aufrufen, der den gespeicherten privaten Temperatursollwert zurückgibt.
Grenzwerttest
Ein Grenzwerttest prüft das Verhalten an einer genauen Grenze oder knapp darüber hinaus und deckt Fehler bei inklusiven oder exklusiven Vergleichen auf.
Ein Sollwertbereich von 10 bis 30 °C benötigt Prüfungen an beiden Endpunkten und bei Werten knapp außerhalb jeder zulässigen Grenze.

H

Hot Module Replacement
Hot Module Replacement aktualisiert ein geändertes Modul in einer laufenden Anwendung und erhält dabei häufig unterstützten Zustand ohne vollständiges Neuladen der Seite.
Die Bearbeitung einer Komponente kann ihr angezeigtes Verhalten aktualisieren und dabei den aktuellen Zustand der Oberfläche erhalten.

I

Import-Map
Eine Import-Map ist eine Browserkonfiguration, die Modulbezeichner URLs zuordnet, sodass Modulimporte Namen verwenden können, die der Browser allein nicht auflösen könnte.
Eine Seite platziert ihre Import-Map vor ihren Modulskripten, um einen kurzen Paketnamen einer Server-URL zuzuordnen.
Inhaltshash
Ein Inhaltshash im Dateinamen einer Ressource ändert sich mit deren Inhalt und hilft Caches, eine neue Datei von einer älteren Version zu unterscheiden.
Eine geänderte Buildressource erhält einen neuen Namen mit Hash, sodass Browser sie anfordern und unveränderte Dateien im Cache behalten können.
Instanz
Eine Instanz ist ein einzelnes aus einer Klasse erstelltes Objekt mit eigenem Zustand und Zugriff auf das von dieser Klasse bereitgestellte Verhalten.
Zwei Rechteckinstanzen können eine Flächenmethode gemeinsam nutzen und dabei unterschiedliche Maße in Zentimetern speichern.
Instanzfeld
Ein Instanzfeld ist eine für jedes aus einer Klasse erstellte Objekt deklarierte Eigenschaft, die jeder Instanz einen eigenen gespeicherten Wert gibt.
Ein mit null initialisiertes Zählerfeld beginnt auf jedem neu erstellten Zählerobjekt separat.
Interface
Ein Interface beschreibt eine erwartete Objektstruktur für die TypeScript-Prüfung, einschließlich der Eigenschaften und Methoden, die diese Struktur benötigt.
Ein Interface für Formen kann einen Namen und eine Flächenmethode verlangen, ohne die Klassenimplementierung bereitzustellen.

K

Kapselung
Kapselung hält internen Zustand hinter einer kontrollierten öffentlichen Schnittstelle, deren Operationen die Regeln für gültige Änderungen einhalten.
Ein Thermostat lässt Aufrufer eine Sollwertänderung anfordern, während sein Setter entscheidet, ob die Eingabe gültig ist.
Klasse
Eine Klasse ist eine Vorlage, mit der mithilfe von Konstruktoren, Feldern und Methoden Objekte mit gemeinsamer Struktur und gemeinsamem Verhalten erstellt werden.
Eine Klasse Rectangle kann mehrere Formen erstellen, deren Flächenmethoden ihre eigenen Breiten und Höhen verwenden.
Komponente
Eine Komponente ist ein wiederverwendbarer Teil einer Benutzeroberfläche, der Markup und Verhalten zusammenfasst, häufig mit Stilen und Zustand, die seine Anzeige beeinflussen.
Eine Navigationskomponente kann auf mehreren Seiten erscheinen, während ihr Interaktionscode an einer Stelle bleibt.
Konstruktor
Ein Konstruktor ist die spezielle Klassenmethode, die beim Erstellen einer neuen Instanz ausgeführt wird und das Objekt anhand übergebener Argumente einrichtet.
Ein Rechteckkonstruktor speichert Breite und Höhe, sodass spätere Methodenaufrufe die Fläche berechnen können.
Konstruktorfunktion
Eine Konstruktorfunktion ist eine Funktion, die mit new zum Initialisieren von Objekten verwendet wird und häufig mit Methoden kombiniert wird, die ihrem Prototyp zugewiesen sind.
Älteres JavaScript kann area nach der Definition einer Konstruktorfunktion an Rectangle.prototype anhängen.

L

Laufzeitvalidierung
Laufzeitvalidierung prüft tatsächliche Werte während der Programmausführung, insbesondere Daten aus externen Quellen, die Typen nicht untersuchen können.
Geparte Netzwerkdaten benötigen eine Prüfung, bevor einem als numerisch deklarierten Feld in einer Berechnung vertraut wird.
Linter
Ein Linter analysiert Quellcode anhand konfigurierter Regeln, um wahrscheinliche Fehler oder riskante Muster zu melden, ohne das Programm auszuführen.
ESLint kann eine falsch geschriebene zurückgegebene Variable erkennen, selbst wenn kein Test die Funktion aufruft, die sie enthält.
Live-Bindung
Eine Live-Bindung verbindet einen importierten Namen mit dem aktuellen Wert des exportierenden Moduls, sodass Änderungen des Exporteurs für Importeure sichtbar bleiben.
Wenn ein Modul einen Zählerstand und eine Funktion zum Erhöhen exportiert, liest ein Importeur nach deren Ausführung den aktualisierten Zählerstand über seinen importierten Namen.
Lockdatei
Eine Lockdatei hält den ausgewählten genauen Abhängigkeitsbaum fest, sodass Installationen Versionen reproduzieren können, ohne jedes Mal neue Auswahlen aufzulösen.
Ein Build verwendet übereinstimmende Paketeinträge mit npm ci, um den festgelegten Baum auf einem anderen Computer wiederherzustellen.

M

Meta-Framework
Ein Meta-Framework ergänzt ein Ökosystem für Benutzeroberflächen um übergreifende Anwendungsfunktionen, häufig einschließlich Routing, Rendern auf dem Server und einer Buildkonfiguration.
Ein Projekt kann eine solche Ebene wählen, wenn es Seitennavigation und auf dem Server gerenderte Ansichten zusammen benötigt.
Methode
Eine Methode ist eine Funktion, die als Teil der Schnittstelle eines Objekts oder einer Klasse bereitgestellt wird und häufig auf dem Objekt arbeitet, das den Aufruf empfängt.
Der Aufruf tile.area() ermöglicht der Methode, die Maße von tile über das Empfängerobjekt this zu lesen.
Methodenüberschreibung
Eine Methodenüberschreibung ist eine Methode einer Unterklasse, die eine gleichnamige geerbte Methode bei Aufrufen ersetzt, die das Verhalten dieser Unterklasse auswählen.
Ein Kreis überschreibt area() und erbt weiterhin die gemeinsame Beschreibungsmethode der Oberklasse.
Minifizierung
Minifizierung verringert die Größe generierten Codes, indem unnötiges Layout entfernt und geeignete Namen verkürzt werden, ohne das beabsichtigte Verhalten zu ändern.
Eine Produktionsdatei kann kürzere lokale Namen haben, obwohl ihr Quellcode aussagekräftige Bezeichner verwendete.
Mixin
Ein Mixin ist eine wiederverwendbare Sammlung von Methoden, die in eine Klasse oder einen Prototyp kopiert wird, um Verhalten hinzuzufügen, ohne eine weitere Oberklasse zu wählen.
Ein Serialisierungs-Mixin kann ansonsten nicht verwandten Klassen über ihre Prototypen Hilfsmethoden bereitstellen.
Modulbezeichner
Ein Modulbezeichner ist die Zeichenkette, die das durch einen Import angeforderte Modul bezeichnet, etwa ein relativer Pfad, eine URL oder ein Paketname.
Der Modulbezeichner "../utils.js" fordert vom Ladesystem ein Modul einen Ordner oberhalb der importierenden Datei an.
Modulnamensraum
Ein Modulnamensraum ist ein Objekt, das die Exporte eines Moduls als Eigenschaften bereitstellt, einschließlich default, wenn ein Standardexport existiert.
Das Warten auf einen dynamischen Import ergibt einen Namensraum, aus dem der Aufrufer den exportierten Konstruktor auswählt.

N

npm
npm ist der mit Node.js bereitgestellte Paketmanager, der aus einem Kommandozeilenwerkzeug und einer zugehörigen öffentlichen Paket-Registry besteht.
Ein Projekt verwendet npm, um Abhängigkeiten zu installieren und die in seinen Paketskripten festgehaltenen Befehle auszuführen.
npm-Skript
Ein npm-Skript ist ein benannter Befehl in package.json, der einer Projektaufgabe einen wiederholbaren Einstiegspunkt über die npm-Kommandozeile gibt.
Das Linter-Skript kann das lokal im Projekt installierte Werkzeug ausführen, wenn ein Teammitglied npm run lint ausführt.
npx
npx ist ein Befehlsausführer, der eine installierte ausführbare Paketdatei verwenden oder anbieten kann, einen Paketbefehl vorübergehend herunterzuladen und auszuführen.
Ein Entwickler kann einen Befehl für einen statischen Server ausprobieren, ohne ihn als dauerhafte Abhängigkeit zum Projekt hinzuzufügen.

Ö

Öffentliche Schnittstelle
Eine öffentliche Schnittstelle ist die Gesamtheit zugänglicher Operationen, über die anderer Code ein Objekt nutzt, ohne von dessen internem Speicher abzuhängen.
Aufrufer können einen Thermostat-Sollwert setzen, selbst wenn die Klasse später ändert, wie sie ihn speichert.

O

Oberklasse
Eine Oberklasse ist die Klasse, von der eine Unterklasse erbt und die Initialisierung und Verhalten für abgeleitete Instanzen bereitstellt.
Die Oberklasse für Formen speichert den gemeinsamen Namen, den ihre Unterklassen für ihre Beschreibungen verwenden.
Objektkomposition
Objektkomposition erzeugt Verhalten, indem ein Objekt andere Objekte erhält, an die es Arbeit delegiert, und drückt eine „hat ein“-Beziehung zwischen ihnen aus.
Ein Bericht enthält einen Benachrichtigungsdienst und fordert ihn auf, eine Nachricht zu senden, ohne selbst eine Art Benachrichtigungsdienst zu werden.

P

Paket
Ein Paket ist ein Ordner, der durch eine package.json-Datei beschrieben wird. Diese hält seine Identität fest und kann Skripte und Abhängigkeiten beschreiben.
Eine lokale Anwendung kann ein npm-Paket sein, selbst wenn ihr private-Flag die Veröffentlichung in der Registry verhindert.
Polymorphie
Polymorphie ermöglicht, dass derselbe Methodenaufruf über eine gemeinsame Schnittstelle für verschiedene Empfängerobjekte unterschiedliche Implementierungen auswählt.
Eine Schleife ruft describe() auf Kreisen und Rechtecken auf und jedes Objekt liefert die passende Fläche.
Private Methode
Eine private Methode ist internes Klassenverhalten mit einem Namen, der mit # beginnt, und hält Hilfsoperationen aus der öffentlichen Schnittstelle des Objekts heraus.
Eine Klasse kann this.#check(value) aufrufen, um Eingaben zu validieren, ohne diese Hilfsmethode für externen Code offenzulegen.
Privates Feld
Ein privates Feld ist ein in einer Klasse deklarierter Speicher mit einem Namen, der mit # beginnt und auf den nur innerhalb der Klasse, die den Namen deklariert, direkt zugegriffen werden kann.
Eine Unterklasse verwendet den öffentlichen Getter ihrer Oberklasse, statt ein von der Oberklasse deklariertes privates Sollwertfeld direkt zu benennen.
Prototyp
Ein Prototyp ist ein Objekt oder null, mit dem ein anderes Objekt verknüpft ist und das durchsucht wird, wenn diesem Objekt eine angeforderte eigene Eigenschaft fehlt.
Eine Instanz kann eine gemeinsam genutzte Flächenmethode auf ihrem Klassenprototyp finden, ohne eine eigene Kopie der Methode zu speichern.
Prototypenkette
Eine Prototypenkette ist die Folge von Verknüpfungen, denen bei der Eigenschaftssuche gefolgt wird und die bei null endet, wenn kein weiterer Prototyp existiert.
Ein Kreis kann seine Beschreibung auf Shape.prototype finden, nachdem die Suche Circle.prototype durchlaufen hat.

R

Reexport
Ein Reexport leitet Exporte eines anderen Moduls durch das aktuelle Modul weiter, sodass eine Datei eine öffentliche Schnittstelle zusammenfassen kann.
Die Indexdatei eines Ordners kann benannte Hilfsfunktionen weiterleiten; eine Export-Stern-Deklaration leitet deren Standardexport nicht weiter.

S

Saubere Installation
Eine saubere Installation erstellt den festgehaltenen Abhängigkeitsbaum mit npm ci neu, benötigt eine passende Lockdatei und ersetzt vorhandene installierte Pakete.
Wenn Paketbeschreibung und Lockdatei nicht übereinstimmen, schlägt eine saubere Installation fehl, statt sie unbemerkt neu zu schreiben.
Schweregrad einer Regel
Der Schweregrad einer Regel bestimmt, ob eine Linter-Regel deaktiviert ist, eine Warnung meldet oder einen Fehler meldet, der den Befehl normalerweise fehlschlagen lässt.
Eine Warnung über eine ungenutzte Variable kann bei einem erfolgreichen Lauf erscheinen, während ein Fehler wegen eines undefinierten Namens ihn fehlschlagen lässt.
Seiteneffekt
Ein Seiteneffekt ist eine beobachtbare Wirkung über die Rückgabe eines Werts hinaus, etwa das Ändern gemeinsam genutzten Zustands, das Aktualisieren der Seite oder das Registrieren von Verhalten.
Ein Modul, das beim Import die Seite ändert, lässt sich ohne Browserumgebung schwerer testen.
Semantische Versionierung
Semantische Versionierung bezeichnet Veröffentlichungen als HAUPTVERSION.NEBENVERSION.PATCH, um inkompatible Änderungen, kompatible Funktionen und kompatible Fehlerkorrekturen zu unterscheiden.
Eine stabile Veröffentlichung mit einer kompatiblen neuen Funktion wechselt von 2.4.1 zu 2.5.0 statt zu einer neuen Hauptversion.
Setter
Ein Setter ist eine Zugriffsmethode, die ausgeführt wird, wenn einer Eigenschaft ein Wert zugewiesen wird, und eine Validierung vor der Änderung des gespeicherten Werts ermöglicht.
Ein Sollwert-Setter kann eine Temperatur außerhalb des Bereichs ablehnen, bevor er sie einem privaten Feld zuweist.
Sicherheitsprüfung der Abhängigkeiten
Eine Sicherheitsprüfung der Abhängigkeiten prüft installierte Paketversionen anhand von Berichten über bekannte Sicherheitslücken und erstellt Befunde zur Prüfung und Behebung.
Ein Prüfbericht sollte gelesen werden, um festzustellen, ob betroffener Code verwendet wird und welche kompatiblen Korrekturen existieren.
Source Map
Eine Source Map verbindet Positionen im generierten Code mit Positionen in ursprünglichen Quelldateien und erleichtert so das Debuggen transformierter Ausgabe.
Ein Stacktrace kann auf die ursprüngliche Funktion verweisen, wenn dem Browser die passende Source Map zur Verfügung steht.
Standardexport
Ein Standardexport stellt den einzigen Standardwert eines Moduls bereit, der ohne geschweifte Klammern unter einem vom Importeur gewählten lokalen Namen importiert wird.
Eine als Standard exportierte Klasse kann als Circle importiert werden, selbst wenn eine andere Datei ihr einen anderen lokalen Namen gibt.
Statische Analyse
Statische Analyse untersucht Code, ohne ihn auszuführen, und nutzt seine geschriebene Struktur und konfigurierte Regeln, um mögliche Probleme zu erkennen.
Eine Diagnose zu einem undefinierten Namen kann im Editor erscheinen, bevor die Anwendung diese Zeile ausführt.
Statische Fabrikmethode
Eine statische Fabrikmethode ist eine Methode auf Klassenebene, die Instanzen unter einem Namen erstellt und zurückgibt, der eine bestimmte Art der Erstellung beschreibt.
Eine Rechteckklasse kann Rectangle.square(5) anbieten, um eine Instanz mit gleichen Seitenlängen zu erstellen.
Statischer Initialisierungsblock
Ein statischer Initialisierungsblock ist ein Block innerhalb einer Klasse, der während der Klassendefinition einmal ausgeführt wird, um die Klasse einzurichten.
Eine Klasse kann in einem statischen Block eine gemeinsame Nachschlagetabelle füllen, ohne diese Einrichtung für jedes Objekt zu wiederholen.
Statisches Mitglied
Ein statisches Mitglied ist ein Feld oder eine Methode, das beziehungsweise die zur Klasse selbst gehört und auf das beziehungsweise die über die Klasse statt über eine einzelne Instanz zugegriffen wird.
Ein gemeinsam genutzter Erstellungszähler wird von der Klasse gelesen, während jedes Objekt seine eigenen Instanzdaten behält.

T

Testgetriebene Entwicklung
Testgetriebene Entwicklung beginnt mit einem fehlschlagenden Verhaltenstest, ergänzt genug Implementierung, damit er besteht, und verbessert dann den Code, während die Tests weiterhin bestehen.
Eine neue Validierungsregel kann zunächst als fehlschlagender Test formuliert werden, bevor ihre Prüfung implementiert wird.
Testrunner
Ein Testrunner findet und führt Tests aus, meldet Ergebnisse und gibt normalerweise einen Fehlercode zurück, wenn ein Test fehlschlägt.
Ein Projektskript kann den Node.js-Testrunner oder Vitest aufrufen, bevor Änderungen an ein Teammitglied weitergegeben werden.
Toleranz
Eine Toleranz ist eine erlaubte numerische Abweichung, mit der Näherungsergebnisse verglichen werden, ohne Fehler jenseits der gewählten Schranke zu akzeptieren.
Ein Gleitkommatest kann eine winzige Rundungsabweichung zulassen und zugleich eine falsche Flächenformel zurückweisen.
Top-Level-await
Top-Level-await ermöglicht einem ES-Modul, während der Auswertung außerhalb einer Funktion zu warten, und verzögert Module, die von dieser Auswertung abhängen.
Ein Einstellungsmodul kann den Abruf der Konfiguration abschließen, bevor sein abhängiges Einstiegsmodul seinen Rumpf startet.
Transitive Abhängigkeit
Eine transitive Abhängigkeit ist ein indirekt benötigtes Paket, weil eine Abhängigkeit des Projekts oder eine von deren Abhängigkeiten es benötigt.
Die Lockdatei hält verschachtelte Pakete fest, selbst wenn die Anwendung diese Pakete nie direkt importiert.
Tree Shaking
Tree Shaking entfernt Code, den die Buildanalyse als ungenutzt und sicher verzichtbar nachweisen kann, und erhält dabei Seiteneffekte, die ausgeführt werden müssen.
Eine ungenutzte reine Hilfsfunktion kann aus der Ausgabe verschwinden, selbst wenn eine andere Hilfsfunktion desselben Moduls erhalten bleibt.
Typannotation
Eine Typannotation gibt im Quellcode die erwartete Art oder Struktur eines Werts an und liefert Informationen für die statische Prüfung.
Eine numerische Parameterannotation hilft einem Editor, einen unpassenden Aufruf abzulehnen, bevor die Funktion ausgeführt wird.
Typdefinition
Eine Typdefinition beschreibt die Typen vorhandenen Codes für Werkzeuge und wird häufig über .d.ts-Dateien oder separate Definitionspakete bereitgestellt.
Eine JavaScript-Bibliothek kann Informationen für die Vervollständigung und Prüfung im Editor liefern, ohne ihren Laufzeitcode umzuschreiben.
Type Stripping
Type Stripping entfernt unterstützte Typsyntax, um die Ausführung zu ermöglichen, ohne selbst zu prüfen, ob die Typen konsistent verwendet werden.
Eine TypeScript-Datei kann durch das Type Stripping von Node.js ausgeführt werden, selbst wenn eine separate Typprüfung einen Fehler melden würde.
TypeScript
TypeScript ergänzt JavaScript um statische Typsyntax und Typprüfung, sodass inkompatible Verwendungen von Werten vor der Ausführung erkannt werden können.
Die Typprüfung kann eine Zeichenkette melden, die an einen als numerisch deklarierten Parameter übergeben wird, selbst wenn JavaScript sie implizit umwandeln könnte.

U

Unittest
Ein Unittest führt einen kleinen Teil eines Programms mit kontrollierten Eingaben aus und prüft, ob sein beobachtetes Verhalten einem erwarteten Ergebnis entspricht.
Ein Rechtecktest kann eine bekannte Fläche prüfen, ohne die Seite zu laden, die das Rechteck anzeigt.
Unterklasse
Eine Unterklasse ist eine mit extends deklarierte Klasse, die von einer Oberklasse erbt und Mitglieder hinzufügen oder geerbtes Verhalten spezialisieren kann.
Eine Quadrat-Unterklasse kann dieselbe Seitenlänge zweimal an den Konstruktor ihrer Rechteck-Oberklasse übergeben.

V

Verdeckung
Verdeckung tritt auf, wenn eine eigene Eigenschaft bei der gewöhnlichen Eigenschaftssuche eine geerbte Eigenschaft mit demselben Namen verbirgt.
Das Löschen der eigenen Schriftgröße eines Objekts kann die unveränderte Standardschriftgröße auf seinem Prototyp wieder sichtbar machen.
Vererbung
Vererbung ermöglicht einer Unterklasse, auf dem Verhalten einer Oberklasse aufzubauen, und drückt eine „ist ein“-Beziehung zwischen den modellierten Objektarten aus.
Ein Kreis erbt die Beschreibung einer Form, stellt aber eine für seine eigene Fläche passende Berechnung bereit.
Versionsbereich
Ein Versionsbereich beschreibt die Versionen, die ein Abhängigkeitseintrag erlaubt, und kann breiter sein als die genau installierte Version.
Ein Caret-Bereich kann eine neuere Nebenversion erlauben, während eine saubere Installation weiterhin einer älteren festgelegten Auswahl folgt.
Verzögert ausgeführtes Skript
Ein verzögert ausgeführtes Skript wartet vor der Ausführung, bis das HTML geparst ist; gewöhnliche Browsermodulskripte verhalten sich standardmäßig so.
Ein gewöhnliches Modul-Einstiegsskript kann Handler an Elemente binden, die zuvor auf der fertig geparsten HTML-Seite erschienen sind.

Z

Zustand
Zustand sind die Daten, die den aktuellen Zustand einer Oberfläche darstellen und deren Änderungen das System für die Benutzeroberfläche veranlassen können, die Anzeige zu aktualisieren.
Die Änderung der ausgewählten Aufgabe kann mehrere Ansichten aktualisieren, die alle von diesem gemeinsam genutzten Zustand abhängen.
Zyklische Abhängigkeit
Eine zyklische Abhängigkeit ist ein Importzyklus, in dem Module direkt oder über andere Module im Graphen voneinander abhängen.
Das Verschieben einer gemeinsamen Hilfsfunktion aus einem Datenmodul und einem Rendermodul in ein drittes unabhängiges Modul kann den Importzyklus zwischen ihnen beseitigen.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten