Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten.Erfahre mehr über dieses Experiment.
Überblick über die JavaScript-Sprache
JavaScript ist eine multiparadigmatische, dynamische Sprache mit Typen und Operatoren, standardmäßig eingebauten Objekten und Methoden. Seine Syntax basiert auf den Sprachen Java und C – viele Strukturen dieser Sprachen gelten auch für JavaScript. JavaScript unterstützt objektorientierte Programmierung mitObjektprototypen und Klassen. Es unterstützt auch funktionale Programmierung, da Funktionenfirst-class Objekte sind, die einfach über Ausdrücke erstellt und wie jedes andere Objekt übergeben werden können.
Diese Seite dient als schneller Überblick über verschiedene JavaScript-Sprachfunktionen und richtet sich an Leser mit Vorkenntnissen in anderen Sprachen wie C oder Java.
In diesem Artikel
Datentypen
Beginnen wir mit den Bausteinen jeder Sprache: den Typen. JavaScript-Programme manipulieren Werte, und all diese Werte gehören einem Typ an. JavaScript bietet siebenPrimitivtypen:
- Number: wird für alle Zahlenwerte (Ganzzahlen und Gleitkommazahlen) verwendet, außer fürsehr große Ganzzahlen.
- BigInt: wird für beliebig große Ganzzahlen verwendet.
- String: wird zur Speicherung von Text verwendet.
- Boolean:
trueundfalse— normalerweise für bedingte Logik verwendet. - Symbol: wird zur Erstellung eindeutiger Identifikatoren verwendet, die nicht kollidieren.
- Undefined: zeigt an, dass einer Variablen kein Wert zugewiesen wurde.
- Null: deutet auf einen vorsätzlichen Nicht-Wert hin.
Alles andere wird als einObjekt bezeichnet. Häufige Objekttypen sind:
Funktionen sind in JavaScript keine speziellen Datenstrukturen - sie sind nur eine spezielle Art von Objekten, die aufgerufen werden können.
Zahlen
JavaScript hat zwei eingebaute numerische Typen: Number und BigInt.
Der Number-Typ ist einIEEE 754 64-Bit-Doppelgenauigkeits-Gleitkommawert, was bedeutet, dass ganze Zahlen sicher zwischen-(253 − 1) und253 − 1 ohne Präzisionsverlust dargestellt werden können, und Gleitkommazahlen können bis zu1.79 × 10308 gespeichert werden. Innerhalb von Zahlen unterscheidet JavaScript nicht zwischen Gleitkommazahlen und Ganzzahlen.
console.log(3 / 2); // 1.5, not 1Einoffensichtlicher Ganzzahl ist also in Wirklichkeitimplizit eine Gleitkommazahl. Aufgrund der IEEE 754-Codierung kann die Gleitkommaarithmetik manchmal ungenau sein.
console.log(0.1 + 0.2); // 0.30000000000000004Bei Operationen, die Ganzzahlen erwarten, wie z.B. bitweise Operationen, wird die Zahl in eine 32-Bit-Ganzzahl konvertiert.
Zahlenliterale können auch Präfixe haben, um die Basis (binär, oktal, dezimal oder hexadezimal) anzugeben, oder ein Exponenten-Suffix.
console.log(0b111110111); // 503console.log(0o767); // 503console.log(0x1f7); // 503console.log(5.03e2); // 503DerBigInt-Typ ist ein Ganzzahl mit beliebiger Länge. Sein Verhalten ist ähnlich wie bei C-Ganzzahltypen (z.B. wird die Division auf null abgeschnitten), außer dass er unbegrenzt wachsen kann. BigInts werden mit einem Zahlenliteral und einemn-Suffix angegeben.
console.log(-3n / 2n); // -1nDie standardmäßigenarithmetischen Operatoren werden unterstützt, einschließlich Addition, Subtraktion, Restarithmetik, usw. BigInts und Nummern können in arithmetischen Operationen nicht gemischt werden.
DasMath-Objekt bietet standardmäßige mathematische Funktionen und Konstanten.
Math.sin(3.5);const circumference = 2 * Math.PI * r;Es gibt drei Möglichkeiten, eine Zeichenkette in eine Zahl umzuwandeln:
parseInt(), das die Zeichenkette für eine Ganzzahl analysiert.parseFloat(), das die Zeichenkette für eine Gleitkommazahl analysiert.- Die
Number()-Funktion, die eine Zeichenkette so analysiert, als wäre sie ein Zahlenliteral und viele verschiedene Zahlenrepräsentationen unterstützt.
Sie können auch dasunäre Plus+ als Abkürzung fürNumber() verwenden.
Zahlenwerte umfassen auchNaN (kurz für "Not a Number") undInfinity. Viele "ungültige mathematische" Operationen werdenNaN zurückgeben - zum Beispiel, wenn versucht wird, eine nicht-numerische Zeichenkette zu parsen, oder bei der Verwendung vonMath.log() auf einem negativen Wert. Die Division durch null erzeugtInfinity (positiv oder negativ).
NaN ist ansteckend: Wenn Sie ihn als Operanden für irgendeine mathematische Operation bereitstellen, wird das Ergebnis ebenfallsNaN sein.NaN ist der einzige Wert in JavaScript, der nicht gleich sich selbst ist (laut IEEE 754-Spezifikation).
Zeichenketten
Zeichenketten in JavaScript sind Sequenzen von Unicode-Zeichen. Dies sollte eine gute Nachricht für jeden sein, der mit Internationalisierung zu tun hatte. Genauer gesagt sind sieUTF-16 kodiert.
console.log("Hello, world");console.log("你好,世界!"); // Nearly all Unicode characters can be written literally in string literalsZeichenketten können mit einfachen oder doppelten Anführungszeichen geschrieben werden — JavaScript unterscheidet nicht zwischen Zeichen und Zeichenketten. Wenn Sie ein einzelnes Zeichen darstellen möchten, verwenden Sie einfach eine Zeichenkette, die aus diesem einzelnen Zeichen besteht.
console.log("Hello"[1] === "e"); // trueUm die Länge einer Zeichenkette (inCode-Einheiten) zu finden, greifen Sie auf ihrelength-Eigenschaft zu.
Zeichenketten habenHilfsmethoden, um die Zeichenkette zu manipulieren und Informationen über die Zeichenkette zu erhalten. Da alle Primitiven von Design aus unveränderlich sind, geben diese Methoden neue Zeichenketten zurück.
Der+ Operator ist für Zeichenketten überladen: Wenn einer der Operanden eine Zeichenkette ist, führt er eine Zeichenkettenverkettung statt einer Zahlenaddition durch. Eine spezielleTemplate Literal-Syntax ermöglicht es, Zeichenketten mit eingebetteten Ausdrücken knapper zu schreiben. Im Gegensatz zu Pythons f-strings oder C#'s interpolierten Zeichenketten verwenden Template Literale Backticks (keine einfachen oder doppelten Anführungszeichen).
const age = 25;console.log("I am " + age + " years old."); // String concatenationconsole.log(`I am ${age} years old.`); // Template literalAndere Typen
JavaScript unterscheidet zwischennull, das einen absichtlichen Nicht-Wert anzeigt (und nur über dasnull-Schlüsselwort zugänglich ist), undundefined, das das Fehlen eines Wertes anzeigt. Es gibt viele Möglichkeiten,undefined zu erhalten:
- Eine
return-Anweisung ohne Wert (return;) gibt implizitundefinedzurück. - Der Zugriff auf eine nicht existierendeObjekt-Eigenschaft (
obj.iDontExist) gibtundefinedzurück. - Eine Variablendeklaration ohne Initialisierung (
let x;) initialisiert die Variable implizit mitundefined.
JavaScript hat einen Boolean-Typ, mit möglichen Wertentrue undfalse, die beide Schlüsselworte sind. Jeder Wert kann basierend auf den folgenden Regeln in einen Boolean umgewandelt werden:
false,0, leere Zeichenketten (""),NaN,nullundundefinedwerden alle zufalse.- Alle anderen Werte werden zu
true.
Sie können diese Umwandlung explizit mit derBoolean()-Funktion durchführen:
Boolean(""); // falseBoolean(234); // trueDies ist jedoch selten notwendig, da JavaScript diese Umwandlung automatisch durchführt, wenn es einen Boolean erwartet, z.B. in einerif-Anweisung (sieheSteuerstrukturen). Aus diesem Grund sprechen wir manchmal von "truthy" und "falsy", was Werte bedeutet, die in booleschen Kontexten zutrue bzw.false werden.
Boolesche Operationen wie&& (logischesund),|| (logischesoder) und! (logischesnicht) werden unterstützt; sieheOperatoren.
Der Symboltyp wird oft verwendet, um eindeutige Identifikatoren zu erstellen. Jedes mit derSymbol()-Funktion erstellte Symbol ist garantiert eindeutig. Außerdem gibt es registrierte Symbole, die gemeinsam genutzte Konstanten sind, und bekannte Symbole, die von der Sprache als „Protokolle“ für bestimmte Operationen verwendet werden. Mehr darüber erfahren Sie imSymbolreferenz.
Variablen
Variablen in JavaScript werden mit einem der drei Schlüsselwörter deklariert:let,const odervar.
let ermöglicht es Ihnen, Block-Level-Variablen zu deklarieren. Die deklarierte Variable ist ab demBlock verfügbar, in dem sie eingeschlossen ist.
let a;let name = "Simon";// myLetVariable is *not* visible out herefor (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) { // myLetVariable is only visible in here}// myLetVariable is *not* visible out hereconst ermöglicht es Ihnen, Variablen zu deklarieren, deren Werte sich niemals ändern sollen. Die Variable ist ab demBlock verfügbar, in dem sie deklariert ist.
const Pi = 3.14; // Declare variable Piconsole.log(Pi); // 3.14Eine mitconst deklarierte Variable kann nicht neu zugewiesen werden.
const Pi = 3.14;Pi = 1; // will throw an error because you cannot change a constant variable.const-Deklarationen verhindern nurNeuzuweisungen — sie verhindern nichtÄnderungen des Variablenwerts, wenn es sich um ein Objekt handelt.
const obj = {};obj.a = 1; // no errorconsole.log(obj); // { a: 1 }var-Deklarationen können überraschende Verhaltensweisen aufweisen (zum Beispiel sind sie nicht blocklokal) und werden in modernem JavaScript-Code nicht empfohlen.
Wenn Sie eine Variable deklarieren, ohne ihr einen Wert zuzuweisen, ist ihr Wertundefined. Sie können keineconst-Variable ohne einen Initialisierer deklarieren, da Sie sie später ohnehin nicht ändern können.
let- undconst-deklarierte Variablen besetzen immer noch den gesamten Umfang, in dem sie definiert sind, und befinden sich in einem Bereich, der alstemporal dead zone bezeichnet wird, vor der tatsächlichen Deklarationszeile. Dies hat einige interessante Wechselwirkungen mit der Variablenschattung, die in anderen Sprachen nicht vorkommen.
function foo(x, condition) { if (condition) { console.log(x); const x = 2; console.log(x); }}foo(1, true);In den meisten anderen Sprachen würde dies "1" und "2" protokollieren, da vor der Zeileconst x = 2x immer noch auf den Parameterx im äußeren Gültigkeitsbereich verweisen sollte. In JavaScript, da jede Deklaration den gesamten Gültigkeitsbereich besetzt, würde dies einen Fehler bei der erstenconsole.log-Anweisung auslösen: "Cannot access 'x' before initialization". Weitere Informationen finden Sie auf der Referenzseite vonlet.
JavaScript istdynamisch typisiert. Typen (wie indem vorherigen Abschnitt beschrieben) sind nur mit Werten, aber nicht mit Variablen assoziiert. Beilet-deklarierten Variablen können Sie ihren Typ immer durch Neuzuweisung ändern.
let a = 1;a = "foo";Operatoren
JavaScripts numerische Operatoren umfassen+,-,*,/,% (Restwert) und** (Potenzierung). Werte werden mittels= zugewiesen. Jeder binäre Operator hat auch ein zusammengesetztes Zuweisungsäquivalent wie+= und-=, die sich zux = x operator y erweitern.
x += 5;x = x + 5;Sie können++ und-- verwenden, um zu inkrementieren bzw. zu dekrementieren. Diese können als Präfix- oder Postfixoperatoren verwendet werden.
Der+ Operator führt auch eine Zeichenkettenverkettung durch:
"hello" + " world"; // "hello world"Wenn Sie einer Zahl (oder einem anderen Wert) eine Zeichenkette hinzufügen, wird alles zuerst in eine Zeichenkette konvertiert. Dies könnte Sie überraschen:
"3" + 4 + 5; // "345"3 + 4 + "5"; // "75"Das Hinzufügen einer leeren Zeichenkette zu etwas ist eine nützliche Möglichkeit, es selbst in eine Zeichenkette zu konvertieren.
Vergleiche in JavaScript können mit<,>,<= und>= durchgeführt werden, die sowohl für Zeichenketten als auch für Zahlen funktionieren. Für die Gleichheit führt derdoppelgleich Operator eine Typumwandlung durch, wenn Sie ihm verschiedene Typen übergeben, mit manchmal interessanten Ergebnissen. Andererseits versucht derdreifachgleich Operator keine Typumwandlung und wird normalerweise bevorzugt.
123 == "123"; // true1 == true; // true123 === "123"; // false1 === true; // falseDer doppelgleich und dreifachgleich-Operator haben auch ihre Ungleichheitsgegenstücke:!= und!==.
JavaScript hat auchbitweise Operatoren undlogische Operatoren. Bemerkenswert ist, dass logische Operatoren nicht nur mit booleschen Werten arbeiten — sie arbeiten nach der „Wahrhaftigkeit“ des Wertes.
const a = 0 && "Hello"; // 0 because 0 is "falsy"const b = "Hello" || "world"; // "Hello" because both "Hello" and "world" are "truthy"Die Operatoren&& und|| verwenden Kurzschlusslogik, was bedeutet, dass die Ausführung ihres zweiten Operanden von ihrem ersten abhängt. Dies ist nützlich, um null Objekte zu überprüfen, bevor auf deren Attribute zugegriffen wird:
const name = o && o.getName();Oder um Werte zwischenzuspeichern (wenn falsy-Werte ungültig sind):
const name = cachedName || (cachedName = getName());Für eine umfassende Liste von Operatoren siehe dieLeitfaden-Seite oder denReferenzabschnitt. Sie könnten besonders an derOperatorpräzedenz interessiert sein.
Grammatik
Die JavaScript-Grammatik ist der C-Familie sehr ähnlich. Es gibt einige Punkte, die erwähnenswert sind:
- Bezeichner können Unicode-Zeichen haben, aber sie dürfen keine derreservierten Wörter sein.
- Kommentare sind üblicherweise
//oder/* */, während viele andere Skriptsprachen wie Perl, Python und Bash#verwenden. - Semikolons sind in JavaScript optional - die Sprachefügt sie automatisch ein, wenn nötig. Es gibt jedoch bestimmte Vorsichtsmaßnahmen, auf die Sie achten sollten, da Semikolons im Gegensatz zu Python immer noch Teil der Syntax sind.
Für einen detaillierten Blick auf die JavaScript-Grammatik siehe dieReferenzseite für lexikalische Grammatik.
Steuerstrukturen
JavaScript hat eine ähnliche Menge an Steuerstrukturen wie andere Sprachen der C-Familie. Bedingte Anweisungen werden vonif undelse unterstützt; Sie können sie verkettet verwenden:
let name = "kittens";if (name === "puppies") { name += " woof";} else if (name === "kittens") { name += " meow";} else { name += "!";}name === "kittens meow";JavaScript hat keinelif, undelse if ist wirklich nur einelse-Zweig, der aus einer einzigenif-Anweisung besteht.
JavaScript verfügt überwhile-Schleifen unddo...while-Schleifen. Die erste ist gut für grundlegende Schleifen; die zweite ist für Schleifen, bei denen Sie sicherstellen möchten, dass der Schleifenkörper mindestens einmal ausgeführt wird:
while (true) { // an infinite loop!}let input;do { input = get_input();} while (inputIsNotValid(input));Diefor-Schleife von JavaScript ist die gleiche wie in C und Java: Sie ermöglicht es Ihnen, die Steuerungsinformationen für Ihre Schleife in einer einzigen Zeile anzugeben.
for (let i = 0; i < 5; i++) { // Will execute 5 times}JavaScript enthält auch zwei andere prominente Schleifen:for...of, die überiterierbare Elemente, insbesondere Arrays, iteriert, undfor...in, die alleenumerable Eigenschaften eines Objekts besucht.
for (const value of array) { // do something with value}for (const property in object) { // do something with object property}Dieswitch-Anweisung kann für mehrere Verzweigungen basierend auf Gleichheitsprüfungen verwendet werden.
switch (action) { case "draw": drawIt(); break; case "eat": eatIt(); break; default: doNothing();}Ähnlich wie in C sind Case-Klauseln konzeptionell die gleichen wieLabels, sodass, wenn Sie einebreak-Anweisung nicht hinzufügen, die Ausführung auf die nächste Ebene "fällt". Sie sind jedoch keine tatsächlichen Sprungtabellen — jeder Ausdruck kann Teil der Case-Klausel sein, nicht nur Zeichen- oder Zahlenliterale, und sie würden nacheinander ausgewertet, bis einer dem Wert entspricht, der abgeglichen wird. Der Vergleich erfolgt zwischen den beiden mit dem===-Operator.
Im Gegensatz zu einigen Sprachen wie Rust sind Kontrollstrukturen in JavaScript Anweisungen, was bedeutet, dass Sie sie nicht einer Variablen zuweisen können, wieconst a = if (x) { 1 } else { 2 }.
JavaScript-Fehler werden mithilfe dertry...catch-Anweisung behandelt.
try { buildMySite("./website");} catch (e) { console.error("Building site failed:", e);}Fehler können mit derthrow-Anweisung ausgelöst werden. Viele eingebaute Operationen können ebenfalls Fehler auslösen.
function buildMySite(siteDirectory) { if (!pathExists(siteDirectory)) { throw new Error("Site directory does not exist"); }}Im Allgemeinen können Sie den Typ des Fehlers, den Sie gerade abgefangen haben, nicht erkennen, da alles von einerthrow-Anweisung geworfen werden kann. Sie können jedoch normalerweise davon ausgehen, dass es sich um eine Instanz vonError handelt, wie im obigen Beispiel. Es gibt einige eingebaute Unterklassen vonError, wieTypeError undRangeError, die Sie verwenden können, um zusätzliche Semantik über den Fehler bereitzustellen. Es gibt keine bedingte Ausnahmebehandlung in JavaScript — wenn Sie nur eine Art von Fehler behandeln möchten, müssen Sie alles erfassen, den Fehlertyp mitinstanceof identifizieren und dann die anderen Fälle neu auslösen.
try { buildMySite("./website");} catch (e) { if (e instanceof RangeError) { console.error("Seems like a parameter is out of range:", e); console.log("Retrying..."); buildMySite("./website"); } else { // Don't know how to handle other error types; throw them so // something else up in the call stack may catch and handle it throw e; }}Wenn ein Fehler von keinemtry...catch im Aufrufstapel abgefangen wurde, wird das Programm beendet.
Für eine umfassende Liste von Steuerflussanweisungen siehe denReferenzabschnitt.
Objekte
JavaScript-Objekte kann man sich als Sammlungen von Schlüssel-Wert-Paaren vorstellen. Als solche sind sie ähnlich:
- Dictionaries in Python.
- Hashes in Perl und Ruby.
- Hash-Tabellen in C und C++.
- HashMaps in Java.
- Assoziative Arrays in PHP.
JavaScript-Objekte sind Hashes. Im Gegensatz zu Objekten in statisch typisierten Sprachen haben Objekte in JavaScript keine festen Formen - Eigenschaften können jederzeit hinzugefügt, gelöscht, umgeordnet, geändert oder dynamisch abgefragt werden. Objekt-Schlüssel sind immerZeichenketten oderSymbole - auch Array-Indizes, die kanonisch Ganzzahlen sind, sind tatsächlich intern Zeichenketten.
Objekte werden üblicherweise mit der Literalsyntax erstellt:
const obj = { name: "Carrot", for: "Max", details: { color: "orange", size: 12, },};Objekteigenschaften könnenzugänglich gemacht werden, indem man den Punkt (.) oder eckige Klammern ([]) verwendet. Wenn man die Punktnotation verwendet, muss der Schlüssel ein gültigerBezeichner sein. Eckige Klammern hingegen ermöglichen das Indizieren des Objekts mit einem dynamischen Schlüsselwert.
// Dot notationobj.name = "Simon";const name = obj.name;// Bracket notationobj["name"] = "Simon";const name = obj["name"];// Can use a variable to define a keyconst userName = prompt("what is your key?");obj[userName] = prompt("what is its value?");Eigenschaftszugriffe können verkettet werden:
obj.details.color; // orangeobj["details"]["size"]; // 12Objekte sind immer Referenzen, sodass, es sei denn, etwas kopiert das Objekt explizit, Änderungen an einem Objekt von außen sichtbar sind.
const obj = {};function doSomething(o) { o.x = 1;}doSomething(obj);console.log(obj.x); // 1Dies bedeutet auch, dass zwei separat erstellte Objekte niemals gleich (!==) sind, weil sie unterschiedliche Referenzen darstellen. Wenn Sie zwei Referenzen auf dasselbe Objekt halten, würde eine Veränderung an einem durch das andere beobachtbar sein.
const me = {};const stillMe = me;me.x = 1;console.log(stillMe.x); // 1Weitere Informationen zu Objekten und Prototypen finden Sie auf derObject-Referenzseite. Weitere Informationen zur Initialisierungssyntax für Objekte finden Sie auf derentsprechenden Referenzseite.
Diese Seite hat alle Details über Objektprototypen und Vererbung weggelassen, weil Sie Vererbung normalerweise mitKlassen erreichen können, ohne den zugrunde liegenden Mechanismus zu berühren (von dem Sie vielleicht gehört haben, dass er schwer verständlich ist). Um mehr darüber zu lernen, sieheVererbung und die Prototypkette.
Arrays
Arrays in JavaScript sind eigentlich eine spezielle Art von Objekt. Sie funktionieren sehr wie normale Objekte (numerische Eigenschaften können natürlich nur mit der[]-Syntax zugegriffen werden), aber sie haben eine magische Eigenschaft namenslength. Diese ist immer um eins höher als der höchste Index im Array.
Arrays werden normalerweise mit Array-Literalen erstellt:
const a = ["dog", "cat", "hen"];a.length; // 3JavaScript-Arrays sind immer noch Objekte — Sie können ihnen beliebige Eigenschaften zuweisen, einschließlich willkürlicher Zahlenindizes. Der einzige "Magie" ist, dasslength automatisch aktualisiert wird, wenn Sie einen bestimmten Index setzen.
const a = ["dog", "cat", "hen"];a[100] = "fox";console.log(a.length); // 101console.log(a); // ['dog', 'cat', 'hen', empty × 97, 'fox']Das oben erhaltene Array wird alsSparses Array bezeichnet, da es nicht besetzte Slots in der Mitte gibt, was dazu führt, dass die Engine es von einem Array in eine Hash-Tabelle deoptimiert. Stellen Sie sicher, dass Ihr Array dicht besiedelt ist!
Indizierung außerhalb der Grenzen wirft keinen Fehler. Wenn Sie einen nicht vorhandenen Array-Index abfragen, erhalten Sie einen Wert vonundefined zurück:
const a = ["dog", "cat", "hen"];console.log(typeof a[90]); // undefinedArrays können beliebige Elemente enthalten und können nach Belieben wachsen oder schrumpfen.
const arr = [1, "foo", true];arr.push({});// arr = [1, "foo", true, {}]Arrays können mit derfor-Schleife durchlaufen werden, wie es in anderen C-ähnlichen Sprachen möglich ist:
for (let i = 0; i < a.length; i++) { // Do something with a[i]}Oder, da Arrays iterable sind, können Sie diefor...of-Schleife verwenden, die gleichbedeutend mit C++/Java'sfor (int x : arr)-Syntax ist:
for (const currentValue of a) { // Do something with currentValue}Arrays verfügen über eine Vielzahl vonArray-Methoden. Viele von ihnen würden das Array durchlaufen — zum Beispiel würdemap() einen Callback auf jedes Array-Element anwenden und ein neues Array zurückgeben:
const babies = ["dog", "cat", "hen"].map((name) => `baby ${name}`);// babies = ['baby dog', 'baby cat', 'baby hen']Funktionen
Zusammen mit Objekten sind Funktionen die Kernkomponenten zum Verständnis von JavaScript. Die grundlegendste Funktionsdeklaration sieht so aus:
function add(x, y) { const total = x + y; return total;}Eine JavaScript-Funktion kann 0 oder mehr Parameter übernehmen. Der Funktionskörper kann so viele Anweisungen enthalten, wie Sie möchten, und kann eigene Variablen deklarieren, die auf diese Funktion lokal beschränkt sind. Diereturn-Anweisung kann verwendet werden, um jederzeit einen Wert zurückzugeben und die Funktion zu beenden. Wenn keine Rückgabeanweisung verwendet wird (oder eine leere Rückgabe ohne Wert), gibt JavaScriptundefined zurück.
Funktionen können mit mehr oder weniger Parametern aufgerufen werden, als sie erwartet. Wenn Sie eine Funktion aufrufen, ohne die erwarteten Parameter zu übergeben, werden diese aufundefined gesetzt. Wenn Sie mehr Parameter übergeben, als erwartet, ignoriert die Funktion die zusätzlichen Parameter.
add(); // NaN// Equivalent to add(undefined, undefined)add(2, 3, 4); // 5// added the first two; 4 was ignoredEs gibt mehrere andere Parametersyntaxen. Zum Beispiel erlaubt dieRest-Parameter-Syntax das Sammeln aller durch den Aufrufer übergebenen zusätzlichen Parameter in einem Array, ähnlich wie Python's*args. (Da JS auf Sprachebene keine benannten Parameter hat, gibt es kein**kwargs.)
function avg(...args) { let sum = 0; for (const item of args) { sum += item; } return sum / args.length;}avg(2, 3, 4, 5); // 3.5Im obigen Code enthält die Variableargs alle Werte, die an die Funktion übergeben wurden.
Der Restparameter speichert alle Argumentenachdem, wo er erklärt wird, aber nicht davor. Mit anderen Worten,function avg(firstValue, ...args) speichert den ersten Wert, der in die Funktion übergeben wird, in der VariablefirstValue und die verbleibenden Argumente inargs.
Wenn eine Funktion eine Liste von Argumenten akzeptiert und Sie diese bereits in einem Array haben, können Sie dieSpread-Syntax im Funktionsaufruf verwenden, um das Array als Liste von Elementen zustreuen. Beispiel:avg(...numbers).
Wir erwähnten, dass JavaScript keine benannten Parameter hat. Es ist jedoch möglich, sie mitObjettdestructuring zu implementieren, das es erlaubt, Objekte bequem zu packen und zu entpacken.
// Note the { } braces: this is destructuring an objectfunction area({ width, height }) { return width * height;}// The { } braces here create a new objectconsole.log(area({ width: 2, height: 3 }));Es gibt auch dieStandardparametersyntax, die es ermöglicht, dass ausgelassene Parameter (oder solche, die alsundefined übergeben werden) einen Standardwert haben.
function avg(firstValue, secondValue, thirdValue = 0) { return (firstValue + secondValue + thirdValue) / 3;}avg(1, 2); // 1, instead of NaNAnonyme Funktionen
JavaScript lässt Sie anonyme Funktionen erstellen — das sind Funktionen ohne Namen. In der Praxis werden anonyme Funktionen in der Regel als Argumente zu anderen Funktionen verwendet, sofort einer Variable zugewiesen, die verwendet werden kann, um die Funktion aufzurufen, oder von einer anderen Funktion zurückgegeben.
// Note that there's no function name before the parenthesesconst avg = function (...args) { let sum = 0; for (const item of args) { sum += item; } return sum / args.length;};Das macht die anonyme Funktion aufrufbar, indemavg() mit einigen Argumenten aufgerufen wird — das heißt, es ist semantisch gleichbedeutend mit der Deklaration der Funktion mit derfunction avg() {}-Deklarationssyntax.
Es gibt eine andere Möglichkeit, anonyme Funktionen zu definieren — durch Verwendung einesPfeilfunktausdrucks.
// Note that there's no function name before the parenthesesconst avg = (...args) => { let sum = 0; for (const item of args) { sum += item; } return sum / args.length;};// You can omit the `return` when simply returning an expressionconst sum = (a, b, c) => a + b + c;Pfeilfunktionen sind nicht semantisch gleichwertig zu Funktionsausdrücken — für weitere Informationen siehe dieReferenzseite.
Es gibt eine weitere Möglichkeit, wie anonyme Funktionen nützlich sein können: Sie können gleichzeitig deklariert und in einem einzigen Ausdruck aufgerufen werden, der alsSofort aufgerufener Funktionsausdruck (IIFE) bezeichnet wird:
(function () { // …})();Für Anwendungsfälle von IIFEs können Sie mehr über dasEmulieren privater Methoden mit Closures lesen.
Rekursive Funktionen
JavaScript erlaubt es Ihnen, Funktionen rekursiv aufzurufen. Dies ist besonders nützlich beim Umgang mit Baumstrukturen, wie sie im DOM des Browsers zu finden sind.
function countChars(elm) { if (elm.nodeType === 3) { // TEXT_NODE return elm.nodeValue.length; } let count = 0; for (let i = 0, child; (child = elm.childNodes[i]); i++) { count += countChars(child); } return count;}Funktionsausdrücke können auch benannt werden, was es ihnen ermöglicht, rekursiv zu sein.
const charsInBody = (function counter(elm) { if (elm.nodeType === 3) { // TEXT_NODE return elm.nodeValue.length; } let count = 0; for (let i = 0, child; (child = elm.childNodes[i]); i++) { count += counter(child); } return count;})(document.body);Der Name, der einem Funktionsausdruck wie oben angegeben wird, ist nur im eigenen Geltungsbereich der Funktion verfügbar. Dies ermöglicht mehr Optimierungen durch die Engine und führt zu lesbarerem Code. Der Name erscheint auch im Debugger und in einigen Stack-Traces, was Ihnen Zeit bei der Fehlersuche sparen kann.
Wenn Sie funktionale Programmierung gewohnt sind, beachten Sie die Leistungsimplikationen der Rekursion in JavaScript. Obwohl die SprachspezifikationTail-Call-Optimierung spezifiziert, hat nur JavaScriptCore (verwendet von Safari) sie implementiert, aufgrund der Schwierigkeit, Stack-Traces wiederherzustellen und der Debuggierbarkeit. Bei tiefer Rekursion ziehen Sie in Erwägung, stattdessen Iteration zu verwenden, um Stapelüberläufe zu vermeiden.
Funktionen sind first-class-Objekte
JavaScript-Funktionen sind first-class-Objekte. Dies bedeutet, dass sie Variablen zugewiesen, als Argumente an andere Funktionen übergeben und von anderen Funktionen zurückgegeben werden können. Darüber hinaus unterstützt JavaScriptClosures ohne explizite Erfassung, was Ihnen erlaubt, bequem funktionale Programmierstile anzuwenden.
// Function returning functionconst add = (x) => (y) => x + y;// Function accepting functionconst babies = ["dog", "cat", "hen"].map((name) => `baby ${name}`);Beachten Sie, dass JavaScript-Funktionen selbst Objekte sind - wie alles andere in JavaScript - und Sie können Eigenschaften zu ihnen hinzufügen oder ändern, wie wir es früher in dem Abschnitt über Objekte gesehen haben.
Innere Funktionen
JavaScript-Funktionsdeklarationen sind innerhalb anderer Funktionen erlaubt. Ein wichtiges Detail von verschachtelten Funktionen in JavaScript ist, dass sie auf Variablen im Gültigkeitsbereich ihrer übergeordneten Funktion zugreifen können:
function parentFunc() { const a = 1; function nestedFunc() { const b = 4; // parentFunc can't use this return a + b; } return nestedFunc(); // 5}Dies bietet eine große Menge an Nutzen beim Schreiben von wartbarem Code. Wenn eine aufgerufene Funktion sich auf eine oder zwei weitere Funktionen stützt, die für keinen anderen Teil Ihres Codes nützlich sind, können Sie diese Hilfsfunktionen innerhalb dieser Funktion verschachteln. Dies hält die Anzahl der Funktionen, die sich im globalen Gültigkeitsbereich befinden, gering.
Dies ist auch ein großartiges Gegenmittel zur Versuchung, globale Variablen zu verwenden. Beim Schreiben von komplexem Code ist es oft verlockend, globale Variablen zu verwenden, um Werte zwischen mehreren Funktionen zu teilen, was zu schwer wartbarem Code führt. Verschachtelte Funktionen können Variablen in ihrem Elternteil teilen, sodass Sie diesen Mechanismus verwenden können, um Funktionen miteinander zu verknüpfen, ohne Ihren globalen Namensraum zu verschmutzen.
Klassen
JavaScript bietet dieclass-Syntax, die der in Sprachen wie Java sehr ähnlich ist.
class Person { constructor(name) { this.name = name; } sayHello() { return `Hello, I'm ${this.name}!`; }}const p = new Person("Maria");console.log(p.sayHello());JavaScript-Klassen sind nur Funktionen, die mit demnew-Operator instanziiert werden müssen. Jedes Mal, wenn eine Klasse instanziiert wird, gibt sie ein Objekt zurück, das die von der Klasse spezifizierten Methoden und Eigenschaften enthält. Klassen erzwingen keine Code-Organisation - zum Beispiel können Sie Funktionen haben, die Klassen zurückgeben, oder Sie können mehrere Klassen pro Datei haben. Hier ist ein Beispiel dafür, wie ad hoc die Erstellung einer Klasse sein kann: es ist nur ein Ausdruck, der von einer Pfeilfunktion zurückgegeben wird. Dieses Muster wird alsMixin bezeichnet.
const withAuthentication = (cls) => class extends cls { authenticate() { // … } };class Admin extends withAuthentication(Person) { // …}Statische Eigenschaften werden durch Voranstellen vonstatic erstellt. Private Felder und Methoden werden durch Voranstellen eines Hash-Zeichens# (nichtprivate) erstellt. Der Hash ist ein integraler Bestandteil des Elementnamens und unterscheidet ihn von einer normalen, mit einem String beschrifteten Eigenschaft. (Denken Sie an# als_ in Python.) Im Gegensatz zu den meisten anderen Sprachen gibt es absolut keinen Weg, ein privates Element außerhalb des Klassenkörpers zu lesen - nicht einmal in abgeleiteten Klassen.
Für eine detaillierte Anleitung zu verschiedenen Klassenfeatures können Sie dieLeitfaden-Seite lesen.
Asynchrone Programmierung
JavaScript ist von Natur aus einsträngig. Es gibt keineParallelisierung; nurNebenläufigkeit. Asynchrone Programmierung wird von einerEreignisschleife angetrieben, die es ermöglicht, eine Reihe von Aufgaben in die Warteschlange zu stellen und auf deren Abschluss zu warten.
Es gibt drei idiomatische Wege, asynchrone Code in JavaScript zu schreiben:
- Callback-basiert (wie
setTimeout()) Promise-basiertasync/await, was ein syntaktischer Zucker für Promises ist
Beispielsweise könnte eine Datei-Leseoperation in JavaScript folgendermaßen aussehen:
// Callback-basedfs.readFile(filename, (err, content) => { // This callback is invoked when the file is read, which could be after a while if (err) { throw err; } console.log(content);});// Code here will be executed while the file is waiting to be read// Promise-basedfs.readFile(filename) .then((content) => { // What to do when the file is read console.log(content); }) .catch((err) => { throw err; });// Code here will be executed while the file is waiting to be read// Async/awaitasync function readFile(filename) { const content = await fs.readFile(filename); console.log(content);}Die Kernsprache spezifiziert keine asynchronen Programmierfunktionen, aber es ist entscheidend, wenn man mit der externen Umgebung interagiert — vonBenutzerberechtigungen anfordern bisDaten abrufen bis hin zumLesen von Dateien. Wenn möglicherweise lang laufende Operationen asynchron sind, stellt dies sicher, dass andere Prozesse weiterlaufen können, während auf den Abschluss dieser Operation gewartet wird — zum Beispiel wird der Browser nicht einfrieren, während auf das Klicken des Benutzers auf eine Schaltfläche gewartet wird, um eine Berechtigung zu erteilen.
Wenn Sie einen asynchronen Wert haben, ist es nicht möglich, seinen Wert synchron zu erhalten. Wenn Sie beispielsweise ein Promise haben, können Sie nur über diethen()-Methode auf das eventuelle Ergebnis zugreifen. Ähnlich kannawait nur in einem asynchronen Kontext verwendet werden, was typischerweise eine asynchrone Funktion oder ein Modul ist. Promises blockierenniemals — nur die Logik, die vom Ergebnis des Promises abhängt, wird verschoben; alles andere wird währenddessen weiter ausgeführt. Wenn Sie ein funktionaler Programmierer sind, erkennen Sie vielleicht Promises alsMonaden an, die mitthen() abgebildet werden können (sie sind jedoch keinerichtigen Monaden, da sie sich selbst abflachen; d.h. Sie können nichtPromise<Promise<T>> haben).
Tatsächlich hat das einsträngige Modell Node.js zu einer beliebten Wahl für serverseitige Programmierung gemacht, aufgrund seiner nicht-blockierenden IO, die den Umgang mit einer großen Anzahl von Datenbank- oder Dateisystemanfragen sehr leistungsfähig macht. Rechenintensive Aufgaben, die reines JavaScript sind, blockieren jedoch weiterhin den Hauptthread. Um eine echte Parallelisierung zu erreichen, müssen Sie möglicherweiseWorker verwenden.
Um mehr über asynchrone Programmierung zu erfahren, können Sie über dieVerwendung von Promises lesen oder dasasynchrone JavaScript-Tutorial befolgen.
Module
JavaScript spezifiziert auch ein Modulsystem, das von den meisten Laufzeitumgebungen unterstützt wird. Ein Modul ist normalerweise eine Datei, die durch ihren Dateipfad oder ihre URL identifiziert wird. Sie können dieimport- undexport-Anweisungen verwenden, um Daten zwischen Modulen auszutauschen:
import { foo } from "./foo.js";// Unexported variables are local to the moduleconst b = 2;export const a = 1;Im Gegensatz zu Haskell, Python, Java usw. ist die Auflösung von JavaScript-Modulen vollständig durch den Host definiert — sie basiert normalerweise auf URLs oder Dateipfaden, sodass relative Dateipfade "einfach funktionieren" und relativ zum Pfad des aktuellen Moduls anstatt zu einem Projekthauptverzeichnis sind.
Die JavaScript-Sprache bietet jedoch keine Standardbibliotheksmodule — alle Kernfunktionalitäten werden durch globale Variablen wieMath undIntl bereitgestellt. Dies ist auf die lange Geschichte von JavaScript zurückzuführen, das kein Modulsystem hatte, und auf die Tatsache, dass das Opt-in in das Modulsystem einige Änderungen an der Laufzeiteinrichtung erfordert.
Verschiedene Laufzeitumgebungen können unterschiedliche Modulsysteme verwenden. Zum Beispiel verwendetNode.js den Paketmanagernpm und basiert hauptsächlich auf Dateisystemen, währendDeno und Browser vollständig URL-basiert sind und Module von HTTP-URLs abgerufen werden können.
Weitere Informationen finden Sie auf derLeitfaden-Seite zu Modulen.
Sprache und Laufzeit
Auf dieser Seite haben wir immer wieder erwähnt, dass bestimmte Funktionensprachebene und anderelaufzeitebene sind.
JavaScript ist eine universelle Skriptsprache. DieKernsprachspezifikation konzentriert sich auf reine Berechnungslogik. Sie behandelt keinen Input/Output — tatsächlich ist das Verhalten eines JavaScript-Programms ohne zusätzliche laufzeitebene APIs (insbesondereconsole.log()) vollständig unbeobachtbar.
Eine Laufzeit oder ein Host ist etwas, das Daten an die JavaScript-Engine (den Interpreter) übermittelt, zusätzliche globale Eigenschaften bereitstellt und Hooks bereitstellt, damit die Engine mit der Außenwelt interagieren kann. Modullösung, Datenlesen, Nachrichten drucken, Netzwerkanfragen senden usw. sind alles laufzeitebene Operationen. Seit seiner Einführung wurde JavaScript in verschiedenen Umgebungen angenommen, wie Browsern (die APIs wieDOM bereitstellen), Node.js (das APIs wieDateisystemzugriff bereitstellt), usw. JavaScript wurde erfolgreich in Webanwendungen (was sein primärer Zweck war), mobilen Apps, Desktop-Apps, serverseitigen Apps, serverlosen Anwendungen, eingebetteten Systemen und mehr integriert. Während Sie die Kernfunktionen von JavaScript lernen, ist es auch wichtig, hostbereitgestellte Funktionen zu verstehen, um das Wissen nutzen zu können. Zum Beispiel können Sie über alleWebplattform-APIs lesen, die von Browsern und manchmal auch von Nicht-Browsern implementiert werden.
Weitere Erkundung
Diese Seite bietet einen sehr grundlegenden Einblick darin, wie verschiedene JavaScript-Funktionen im Vergleich zu anderen Sprachen stehen. Wenn Sie mehr über die Sprache selbst und die Feinheiten jeder Funktion erfahren möchten, können Sie denJavaScript-Leitfaden und dieJavaScript-Referenz lesen.
Es gibt einige wesentliche Teile der Sprache, die wir aufgrund von Platz und Komplexität weggelassen haben, die Sie jedoch selbst erkunden können: