Im Folgenden finden Sie eine Übersicht über die Standardformulare zur Erstellung von Funktionen: (Ursprünglich für eine andere Frage geschrieben, aber angepasst, nachdem sie in die kanonische Frage verschoben wurde).
Bedingungen:
Die kurze Liste:
-
Funktionserklärung
-
"Anonym" function
Ausdruck (die trotz der Bezeichnung manchmal Funktionen mit Namen erzeugen)
-
Benannt function
Ausdruck
-
Initialisierung von Zugriffsfunktionen (ES5+)
-
Pfeil-Funktionsausdruck (ES2015+) (die, wie anonyme Funktionsausdrücke, keinen expliziten Namen beinhalten und dennoch Funktionen mit Namen erstellen können)
-
Methodendeklaration im Objektinitialisierer (ES2015+)
-
Konstruktor- und Methodendeklarationen in class
(ES2015+)
Funktionserklärung
Die erste Form ist eine Funktionsdeklaration die wie folgt aussieht:
function x() {
console.log('x');
}
Eine Funktionsdeklaration ist eine 宣言 Es ist keine Aussage oder ein Ausdruck. Als solcher folgen Sie ihm nicht mit einem ;
(obwohl dies harmlos ist).
Eine Funktionsdeklaration wird verarbeitet, wenn die Ausführung in den Kontext eintritt, in dem sie erscheint, antes de ein schrittweiser Code ausgeführt wird. Die erstellte Funktion wird mit einem eigenen Namen versehen ( x
im obigen Beispiel), und dieser Name wird in den Bereich gesetzt, in dem die Erklärung erscheint.
Da er vor dem Schritt-für-Schritt-Code im gleichen Kontext verarbeitet wird, können Sie Dinge wie diese tun:
x(); // Works even though it's above the declaration
function x() {
console.log('x');
}
Bis ES2015 war in der Spezifikation nicht festgelegt, was eine JavaScript-Engine tun soll, wenn Sie eine Funktionsdeklaration innerhalb einer Kontrollstruktur wie try
, if
, switch
, while
usw., etwa so:
if (someCondition) {
function foo() { // <===== HERE THERE
} // <===== BE DRAGONS
}
Und da sie verarbeitet werden antes de Schritt-für-Schritt-Code ausgeführt wird, ist es knifflig zu wissen, was zu tun ist, wenn sie sich in einer Kontrollstruktur befinden.
Obwohl dies nicht der Fall war angegeben bis ES2015 war es ein zulässige Erweiterung um Funktionsdeklarationen in Blöcken zu unterstützen. Unglücklicherweise (und zwangsläufig) taten die verschiedenen Motoren unterschiedliche Dinge.
Ab ES2015 sagt die Spezifikation, was zu tun ist. In der Tat gibt es drei verschiedene Dinge zu tun:
- Wenn im losen Modus no in einem Webbrowser soll die JavaScript-Engine vor allem eines tun
- Im losen Modus eines Webbrowsers soll die JavaScript-Engine etwas anderes tun
- Wenn in Streng Modus (Browser oder nicht), soll die JavaScript-Engine noch etwas anderes tun
Die Regeln für die losen Modi sind kompliziert, aber in Streng Modus sind Funktionsdeklarationen in Blöcken einfach: Sie sind lokal für den Block (sie haben Blockumfang was ebenfalls neu in ES2015 ist), und sie werden an die Spitze des Blocks gehievt. So:
"use strict";
if (someCondition) {
foo(); // Works just fine
function foo() {
}
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
// because it's not in the same block)
"Anonym" function
Ausdruck
Die zweite gängige Form wird als anonymer Funktionsausdruck :
var y = function () {
console.log('y');
};
Wie alle Ausdrücke wird er ausgewertet, wenn er bei der schrittweisen Ausführung des Codes erreicht wird.
In ES5 hat die so erstellte Funktion keinen Namen (sie ist anonym). In ES2015 wird der Funktion ein Name zugewiesen, wenn möglich, indem er aus dem Kontext abgeleitet wird. Im obigen Beispiel würde der Name lauten y
. Etwas Ähnliches wird getan, wenn die Funktion der Wert eines Eigenschaftsinitialisierers ist. (Für Details darüber, wann dies geschieht und die Regeln, suchen Sie nach SetFunctionName
im die Spezifikation - es scheint überall den Ort.)
Benannt function
Ausdruck
Die dritte Form ist eine benannter Funktionsausdruck ("NFE"):
var z = function w() {
console.log('zw')
};
Die so erzeugte Funktion hat einen eigenen Namen ( w
in diesem Fall). Wie alle Ausdrücke wird auch dieser ausgewertet, wenn er bei der schrittweisen Ausführung des Codes erreicht wird. Der Name der Funktion lautet no zu dem Bereich hinzugefügt, in dem der Ausdruck erscheint; der Name ist im Geltungsbereich der Funktion selbst:
var z = function w() {
console.log(typeof w); // "function"
};
console.log(typeof w); // "undefined"
Beachten Sie, dass NFEs häufig eine Quelle von Fehlern für JavaScript-Implementierungen gewesen sind. IE8 und frühere Versionen behandeln NFEs zum Beispiel völlig falsch Damit wurden zwei verschiedene Funktionen zu zwei verschiedenen Zeitpunkten geschaffen. Frühe Versionen von Safari hatten ebenfalls Probleme. Die gute Nachricht ist, dass aktuelle Versionen von Browsern (IE9 und höher, aktueller Safari) diese Probleme nicht mehr haben. (Zum Zeitpunkt der Erstellung dieses Artikels ist der IE8 leider immer noch weit verbreitet, so dass die Verwendung von NFEs mit Code für das Web im Allgemeinen immer noch problematisch ist).
Initialisierung von Zugriffsfunktionen (ES5+)
Manchmal schleichen sich Funktionen weitgehend unbemerkt ein; das ist der Fall bei Accessorfunktionen . Hier ist ein Beispiel:
var obj = {
value: 0,
get f() {
return this.value;
},
set f(v) {
this.value = v;
}
};
console.log(obj.f); // 0
console.log(typeof obj.f); // "number"
Beachten Sie, dass ich bei der Verwendung der Funktion nicht ()
! Das liegt daran, dass es ein Accessorfunktion für eine Immobilie. Wir erhalten und setzen die Eigenschaft auf die normale Weise, aber hinter den Kulissen wird die Funktion aufgerufen.
Sie können auch Accessor-Funktionen erstellen mit Object.defineProperty
, Object.defineProperties
und das weniger bekannte zweite Argument zu Object.create
.
Pfeil-Funktionsausdruck (ES2015+)
ES2015 bringt uns die Pfeilfunktion . Hier ist ein Beispiel:
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6
Siehe das n => n * 2
Ding, das sich in der map()
anrufen? Das ist eine Funktion.
Ein paar Dinge zu den Pfeilfunktionen:
-
Sie haben keine eigene this
. Stattdessen haben sie zu Ende gehen el this
des Kontextes, in dem sie definiert sind. (Sie schließen auch über arguments
und, sofern zutreffend, super
.) Dies bedeutet, dass die this
in ihnen ist die gleiche wie die this
wo sie erstellt werden, und können nicht geändert werden.
-
Wie Sie sicher schon bemerkt haben, verwenden Sie das Schlüsselwort function
; stattdessen verwenden Sie =>
.
Le site n => n * 2
Das obige Beispiel ist eine Form von ihnen. Wenn Sie mehrere Argumente haben, um die Funktion zu übergeben, verwenden Sie Parens:
var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6
(Denken Sie daran, dass Array#map
übergibt den Eintrag als erstes Argument und den Index als zweites).
In beiden Fällen ist der Körper der Funktion nur ein Ausdruck; der Rückgabewert der Funktion wird automatisch das Ergebnis dieses Ausdrucks sein (Sie verwenden keine explizite return
).
Wenn Sie mehr als nur einen einzigen Ausdruck verwenden, sollten Sie {}
und eine ausdrückliche return
(wenn Sie einen Wert zurückgeben müssen), wie üblich:
var a = [
{first: "Joe", last: "Bloggs"},
{first: "Albert", last: "Bloggs"},
{first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
var rv = a.last.localeCompare(b.last);
if (rv === 0) {
rv = a.first.localeCompare(b.first);
}
return rv;
});
console.log(JSON.stringify(a));
Die Version ohne { ... }
wird als Pfeilfunktion mit einer Ausdrucksorgan o prägnanter Aufbau . (Auch: A kurz und bündig Pfeilfunktion). Die mit { ... }
die den Körper definiert, ist eine Pfeilfunktion mit einer Funktionsrumpf . (Auch: A Ausführlich Pfeilfunktion).
Methodendeklaration im Objektinitialisierer (ES2015+)
ES2015 erlaubt eine kürzere Form der Deklaration einer Eigenschaft, die auf eine Funktion namens Methodendefinition Es sieht folgendermaßen aus:
var o = {
foo() {
}
};
das fast gleichwertige in ES5 und früher wäre:
var o = {
foo: function foo() {
}
};
Der Unterschied (abgesehen von der Ausführlichkeit) besteht darin, dass eine Methode Folgendes verwenden kann super
aber eine Funktion nicht. Wenn Sie also zum Beispiel ein Objekt haben, das (sagen wir) definiert valueOf
unter Verwendung der Methodensyntax, könnte es super.valueOf()
um den Wert zu erhalten Object.prototype.valueOf
zurückgegeben hätte (bevor es vermutlich etwas anderes damit gemacht hätte), während die ES5-Version Folgendes tun müsste Object.prototype.valueOf.call(this)
stattdessen.
Das bedeutet auch, dass die Methode einen Verweis auf das Objekt hat, für das sie definiert wurde. Wenn dieses Objekt also temporär ist (zum Beispiel, wenn Sie es in Object.assign
als eines der Quellobjekte), Methodensyntax könnte bedeutet, dass das Objekt im Speicher verbleibt, obwohl es andernfalls hätte entsorgt werden können (wenn die JavaScript-Engine diese Situation nicht erkennt und behandelt, wenn keine der Methoden mit super
).
Konstruktor- und Methodendeklarationen in class
(ES2015+)
ES2015 bringt uns class
Syntax, einschließlich deklarierter Konstruktoren und Methoden:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
Oben sind zwei Funktionen deklariert: Eine für den Konstruktor, der den Namen Person
und eine für getFullName
die eine Funktion ist, die der Person.prototype
.