Ich habe kürzlich damit begonnen, den JavaScript-Code eines anderen zu pflegen. Ich behebe Fehler, füge Funktionen hinzu und versuche auch, den Code aufzuräumen und konsistenter zu machen.
Der vorherige Entwickler hat zwei Arten der Deklaration von Funktionen verwendet, und ich kann nicht herausfinden, ob es einen Grund dafür gibt oder nicht.
Die zwei Möglichkeiten sind:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Was sind die Gründe für die Verwendung dieser beiden unterschiedlichen Methoden und welche Vor- und Nachteile hat jede? Gibt es etwas, das mit einer Methode gemacht werden kann, das mit der anderen nicht gemacht werden kann?
javascript
function
syntax
idioms
Richard Garside
quelle
quelle
var a = 1; var b = 2;
wirdvar a; var b; a = 1; b = 2
. Wenn Sie also functionOne deklarieren, wird es deklariert, aber sein Wert wird nicht sofort festgelegt. Da functionTwo nur eine Deklaration ist, wird sie ganz oben in den Geltungsbereich gestellt. # 2 functionTwo ermöglicht den Zugriff auf die Eigenschaft name. Dies ist sehr hilfreich, wenn Sie versuchen, etwas zu debuggen.function f(){}
vsvar f = function(){};
.Antworten:
Der Unterschied besteht darin, dass
functionOne
es sich um einen Funktionsausdruck handelt, der nur dann definiert wird, wenn diese Zeile erreicht ist, währendfunctionTwo
es sich um eine Funktionsdeklaration handelt, die definiert wird, sobald die umgebende Funktion oder das umgebende Skript ausgeführt wird (aufgrund des Anhebens ).Zum Beispiel ein Funktionsausdruck:
Und eine Funktionsdeklaration:
In der Vergangenheit wurden in Blöcken definierte Funktionsdeklarationen zwischen Browsern inkonsistent behandelt. Der strikte Modus (eingeführt in ES5) löste dieses Problem, indem Funktionsdeklarationen für den umschließenden Block festgelegt wurden.
quelle
functionOne
lediglich um eine Variable, der eine anonyme Funktion zugewiesen ist, währendfunctionTwo
es sich tatsächlich um eine benannte Funktion handelt. Rufen Sie.toString()
beide an, um den Unterschied zu sehen. Dies ist in einigen Fällen von Bedeutung, in denen Sie den Namen einer Funktion programmgesteuert abrufen möchten.function expression
der zweite ist einfunction declaration
. Sie können mehr über das Thema hier lesen: javascriptweblog.wordpress.com/2010/07/06/…Zuerst möchte ich Greg korrigieren:
function abc(){}
hat auch einen Gültigkeitsbereich - der Nameabc
wird in dem Bereich definiert, in dem diese Definition vorkommt. Beispiel:Zweitens ist es möglich, beide Stile zu kombinieren:
xyz
wird wie gewohnt definiert,abc
ist in allen Browsern außer Internet Explorer undefiniert - verlassen Sie sich nicht darauf, dass es definiert wird. Aber es wird in seinem Körper definiert:Wenn Sie Alias-Funktionen in allen Browsern verwenden möchten, verwenden Sie diese Art von Deklaration:
In diesem Fall sind beide
xyz
undabc
Aliase desselben Objekts:Ein zwingender Grund für die Verwendung des kombinierten Stils ist das Attribut "name" von Funktionsobjekten ( von Internet Explorer nicht unterstützt ). Grundsätzlich, wenn Sie eine Funktion wie definieren
sein Name wird automatisch vergeben. Aber wenn Sie es wie definieren
Der Name ist leer - wir haben eine anonyme Funktion erstellt und einer Variablen zugewiesen.
Ein weiterer guter Grund für die Verwendung des kombinierten Stils besteht darin, einen kurzen internen Namen zu verwenden, um auf sich selbst zu verweisen, und externen Benutzern einen langen, nicht widersprüchlichen Namen bereitzustellen:
Im obigen Beispiel können wir dasselbe mit einem externen Namen tun, aber es ist zu unhandlich (und langsamer).
(Eine andere Möglichkeit, sich auf sich selbst zu beziehen, ist die Verwendung
arguments.callee
, die noch relativ lang ist und im strengen Modus nicht unterstützt wird.)Tief im Inneren behandelt JavaScript beide Anweisungen unterschiedlich. Dies ist eine Funktionsdeklaration:
abc
hier ist überall im aktuellen Umfang definiert:Es wurde auch durch eine
return
Aussage gehisst :Dies ist ein Funktionsausdruck:
xyz
hier wird ab dem Zeitpunkt der Zuordnung definiert:Funktionsdeklaration vs. Funktionsausdruck ist der wahre Grund, warum Greg einen Unterschied zeigt.
Lustige Tatsache:
Persönlich bevorzuge ich die Deklaration "Funktionsausdruck", da ich auf diese Weise die Sichtbarkeit steuern kann. Wenn ich die Funktion wie definiere
Ich weiß, dass ich die Funktion lokal definiert habe. Wenn ich die Funktion wie definiere
Ich weiß, dass ich es global definiert habe, vorausgesetzt, ich habe
abc
nirgendwo in der Kette der Bereiche definiert. Dieser Definitionsstil ist auch bei Verwendung im Inneren belastbareval()
. Während der Definitionhängt vom Kontext ab und lässt Sie möglicherweise raten, wo es tatsächlich definiert ist, insbesondere im Fall von
eval()
- die Antwort lautet: Es hängt vom Browser ab.quelle
var abc = function(){}; console.log(abc.name);
produziert""
nicht mehr, sondern"abc"
.Hier ist der Überblick über die Standardformulare, mit denen Funktionen erstellt werden: (Ursprünglich für eine andere Frage geschrieben, aber angepasst, nachdem sie in die kanonische Frage verschoben wurden.)
Bedingungen:
Die Schnellliste:
Funktionserklärung
"Anonymer"
function
Ausdruck (der trotz des Begriffs manchmal Funktionen mit Namen erstellt)Benannter
function
AusdruckAccessor Function Initializer (ES5 +)
Pfeilfunktionsausdruck (ES2015 +) (der wie anonyme Funktionsausdrücke keinen expliziten Namen enthält und dennoch Funktionen mit Namen erstellen kann)
Methodendeklaration im Objektinitialisierer (ES2015 +)
Konstruktor- und Methodendeklarationen in
class
(ES2015 +)Funktionserklärung
Die erste Form ist eine Funktionsdeklaration , die folgendermaßen aussieht:
Eine Funktionsdeklaration ist eine Deklaration . Es ist keine Aussage oder Ausdruck. Als solches 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 angezeigt wird, bevor ein schrittweiser Code ausgeführt wird. Die von ihr erstellte Funktion erhält einen Eigennamen (
x
im obigen Beispiel), und dieser Name wird in den Bereich eingefügt, in dem die Deklaration angezeigt wird.Da es vor jedem Schritt-für-Schritt-Code im selben Kontext verarbeitet wird, können Sie Folgendes tun:
Bis ES2015, decken die Spezifikation nicht , was ein JavaScript - Engine tun sollten , wenn Sie eine Funktionsdeklaration innerhalb einer Kontrollstruktur wie setzen
try
,if
,switch
,while
usw., wie folgt aus :Und da sie verarbeitet werden, bevor Schritt-für-Schritt-Code ausgeführt wird, ist es schwierig zu wissen, was zu tun ist, wenn sie sich in einer Kontrollstruktur befinden.
Obwohl dies nicht zu tun wurde angegeben , bis ES2015, war es eine zulässige Verlängerung auf Unterstützung Funktionsdeklarationen in Blöcken. Leider (und unvermeidlich) haben verschiedene Motoren unterschiedliche Dinge getan.
Ab ES2015 steht in der Spezifikation, was zu tun ist. In der Tat gibt es drei verschiedene Dinge zu tun:
Die Regeln für die losen Modi sind schwierig, aber im strengen Modus sind Funktionsdeklarationen in Blöcken einfach: Sie sind lokal für den Block (sie haben einen Blockumfang , der auch in ES2015 neu ist) und werden nach oben gehisst des Blocks. Damit:
"Anonymer"
function
AusdruckDie zweite gebräuchliche Form heißt anonymer Funktionsausdruck :
Wie alle Ausdrücke wird es ausgewertet, wenn es bei der schrittweisen Ausführung des Codes erreicht wird.
In ES5 hat die dadurch erstellte Funktion keinen Namen (sie ist anonym). In ES2015 wird der Funktion nach Möglichkeit ein Name zugewiesen, indem sie aus dem Kontext abgeleitet wird. Im obigen Beispiel wäre der Name
y
. Ähnliches geschieht, wenn die Funktion der Wert eines Eigenschaftsinitialisierers ist. (Einzelheiten dazu und in den Regeln finden SieSetFunctionName
in der Spezifikation. Es wird überall angezeigt .)Benannter
function
AusdruckDie dritte Form ist ein benannter Funktionsausdruck ("NFE"):
Die dadurch erstellte Funktion hat einen Eigennamen (
w
in diesem Fall). Wie alle Ausdrücke wird dies ausgewertet, wenn es bei der schrittweisen Ausführung des Codes erreicht wird. Der Name der Funktion wird nicht zu dem Bereich hinzugefügt, in dem der Ausdruck angezeigt wird. Der Name befindet sich im Gültigkeitsbereich der Funktion selbst:Beachten Sie, dass NFEs häufig Fehlerquellen für JavaScript-Implementierungen waren. IE8 und frühere Versionen behandeln NFEs beispielsweise völlig falsch und erstellen zwei verschiedene Funktionen zu zwei verschiedenen Zeiten. Frühere Versionen von Safari hatten ebenfalls Probleme. Die gute Nachricht ist, dass aktuelle Versionen von Browsern (IE9 und höher, aktuelle Safari) diese Probleme nicht mehr haben. (Zum jetzigen Zeitpunkt ist IE8 leider weiterhin weit verbreitet, weshalb die Verwendung von NFEs mit Code für das Web im Allgemeinen immer noch problematisch ist.)
Accessor Function Initializer (ES5 +)
Manchmal können sich Funktionen weitgehend unbemerkt einschleichen. Dies ist bei Accessor-Funktionen der Fall . Hier ist ein Beispiel:
Beachten Sie, dass ich die Funktion nicht verwendet habe
()
! Das liegt daran, dass es sich um eine Accessor-Funktion für eine Eigenschaft handelt. Wir erhalten und setzen die Eigenschaft auf normale Weise, aber hinter den Kulissen wird die Funktion aufgerufen.Sie können Accessor-Funktionen auch mit
Object.defineProperty
,Object.defineProperties
und dem weniger bekannten zweiten Argument für erstellenObject.create
.Pfeilfunktionsausdruck (ES2015 +)
ES2015 bringt uns die Pfeil - Funktion . Hier ist ein Beispiel:
Sehen Sie das
n => n * 2
Ding immap()
Anruf versteckt ? Das ist eine Funktion.Ein paar Dinge über Pfeilfunktionen:
Sie haben keine eigenen
this
. Stattdessen sie dicht über diethis
von dem Kontext , in dem sie definiert sind. (Sie schließen aucharguments
und, falls relevant,.super
) Dies bedeutet, dass dasthis
in ihnen dasselbe ist wie dasthis
in dem sie erstellt wurden, und nicht geändert werden kann.Wie Sie oben bemerkt haben, verwenden Sie das Schlüsselwort nicht
function
. stattdessen verwenden Sie=>
.Das
n => n * 2
obige Beispiel ist eine Form davon. Wenn Sie mehrere Argumente haben, um die Funktion zu übergeben, verwenden Sie parens:(Erinnere dich daran
Array#map
der Eintrag als erstes Argument und der Index als zweites übergeben werden.)In beiden Fällen ist der Funktionskörper nur ein Ausdruck; Der Rückgabewert der Funktion ist automatisch das Ergebnis dieses Ausdrucks (Sie verwenden keinen expliziten Ausdruck
return
).Wenn Sie mehr als nur einen einzelnen Ausdruck ausführen, verwenden Sie wie gewohnt
{}
einen expliziten Ausdruckreturn
(wenn Sie einen Wert zurückgeben müssen):Die Version ohne
{ ... }
wird als Pfeilfunktion mit einem Ausdruckskörper oder einem prägnanten Körper bezeichnet . (Auch: Eine prägnante Pfeilfunktion.) Diejenige mit der{ ... }
Definition des Körpers ist eine Pfeilfunktion mit einem Funktionskörper . (Auch: Eine ausführliche Pfeilfunktion.)Methodendeklaration im Objektinitialisierer (ES2015 +)
ES2015 ermöglicht eine kürzere Form der Deklaration einer Eigenschaft, die auf eine Funktion verweist, die als Methodendefinition bezeichnet wird . es sieht aus wie das:
Das fast Äquivalent in ES5 und früher wäre:
Der Unterschied (außer der Ausführlichkeit) besteht darin, dass eine Methode verwendet werden kann
super
, eine Funktion jedoch nicht. Wenn Sie beispielsweise ein Objekt hätten, dasvalueOf
mithilfe der Methodensyntax definiert (z. B.) , könnte es verwendet werdensuper.valueOf()
, um den WertObject.prototype.valueOf
abzurufen (bevor Sie vermutlich etwas anderes damit tun), während die ES5-Version diesObject.prototype.valueOf.call(this)
stattdessen tun müsste .Das bedeutet auch , dass das Verfahren einen Verweis auf das Objekt hat es auf definiert wurde, also wenn das Objekt nur vorübergehend ist (zum Beispiel, ich bin es in vorbei
Object.assign
als einer der Quellobjekt), Methode Syntax könnte bedeuten , dass das Objekt gehalten wird , im Speicher, wenn es sonst zu einer Müllabfuhr hätte kommen können (wenn die JavaScript-Engine diese Situation nicht erkennt und behandelt, wenn keine der Methoden verwendetsuper
).Konstruktor- und Methodendeklarationen in
class
(ES2015 +)ES2015 bringt uns
class
Syntax, einschließlich deklarierter Konstruktoren und Methoden:Oben sind zwei Funktionsdeklarationen aufgeführt: Eine für den Konstruktor, der den Namen erhält
Person
, und eine fürgetFullName
die Funktion, der eine Funktion zugewiesen istPerson.prototype
.quelle
w
einfach ignoriert?Wenn Sie über den globalen Kontext sprechen, erstellen sowohl die
var
Anweisung als auch aFunctionDeclaration
am Ende eine nicht löschbare Eigenschaft für das globale Objekt, aber der Wert von beiden kann überschrieben werden .Der subtile Unterschied zwischen den beiden Möglichkeiten besteht darin, dass beim Ausführen des Variableninstanziierungsprozesses (vor der eigentlichen Codeausführung) alle mit deklarierten Bezeichner mit
var
initialisiertundefined
werden und diejenigen, die von denFunctionDeclaration
's verwendet werden, seit diesem Moment verfügbar sind, zum Beispiel:Die Zuordnung der
bar
FunctionExpression
erfolgt bis zur Laufzeit.Eine von a erstellte globale Eigenschaft
FunctionDeclaration
kann wie ein variabler Wert problemlos überschrieben werden, z. B.:Ein weiterer offensichtlicher Unterschied zwischen Ihren beiden Beispielen besteht darin, dass die erste Funktion keinen Namen hat, die zweite jedoch, was beim Debuggen (dh beim Überprüfen eines Aufrufstapels) sehr nützlich sein kann.
Über Ihr bearbeitetes erstes Beispiel (
foo = function() { alert('hello!'); };
) handelt es sich um eine nicht deklarierte Aufgabe. Ich möchte Sie dringend dazu ermutigen, immer dasvar
Schlüsselwort zu verwenden.Mit einer Aufgabe, ohne die
var
Wenn Anweisung der referenzierte Bezeichner nicht in der Bereichskette gefunden wird, wird er zu einer löschbaren Eigenschaft des globalen Objekts.Auch nicht deklarierte Zuweisungen werfen a
ReferenceError
ECMAScript 5 im Strict Mode .Muss gelesen werden:
Hinweis : Diese Antwort wurde aus einer anderen Frage zusammengeführt , bei der der Hauptzweifel und das Missverständnis des OP darin bestand, dass mit a deklarierte Kennungen
FunctionDeclaration
nicht überschrieben werden konnten, was nicht der Fall ist.quelle
Die beiden Code-Schnipsel, die Sie dort gepostet haben, verhalten sich für fast alle Zwecke gleich.
Der Unterschied im Verhalten ist jedoch der bei der ersten Variante (
var functionOne = function() {}
, dass diese Funktion ) erst nach diesem Punkt im Code aufgerufen werden kann.Mit der zweiten Variante (
function functionTwo()
) steht die Funktion für Code zur Verfügung, der über der deklarierten Funktion ausgeführt wird.Dies liegt daran, dass bei der ersten Variante die Funktion zur
foo
Laufzeit der Variablen zugewiesen wird. Im zweiten Fall wird die Funktion zur Analysezeit dieser Kennung zugewiesenfoo
.Weitere technische Informationen
JavaScript bietet drei Möglichkeiten zum Definieren von Funktionen.
eval()
, was seine Probleme hat.quelle
Eine bessere Erklärung für Gregs Antwort
Warum kein Fehler? Uns wurde immer beigebracht, dass Ausdrücke von oben nach unten ausgeführt werden (??)
Weil:
Dies bedeutet, dass der Code wie folgt lautet:
Beachten Sie, dass der Zuweisungsteil der Deklarationen nicht gehisst wurde. Nur der Name wird gehisst.
Bei Funktionsdeklarationen wird jedoch auch der gesamte Funktionskörper angehoben :
quelle
Andere Kommentatoren haben bereits den semantischen Unterschied der beiden oben genannten Varianten behandelt. Ich wollte einen stilistischen Unterschied feststellen: Nur die Variation "Zuweisung" kann eine Eigenschaft eines anderen Objekts festlegen.
Ich baue oft JavaScript-Module mit einem Muster wie dem folgenden:
Mit diesem Muster verwenden alle Ihre öffentlichen Funktionen die Zuweisung, während Ihre privaten Funktionen die Deklaration verwenden.
(Beachten Sie auch, dass für die Zuweisung nach der Anweisung ein Semikolon erforderlich sein sollte, während die Deklaration dies verbietet.)
quelle
var foo = function(){...}
Syntax auch für private Variablen verwendet.function window.onload() {}
war eine Sache.)Ein Beispiel dafür, wann Sie die erste Methode der zweiten vorziehen sollten, ist, wenn Sie vermeiden müssen, die vorherigen Definitionen einer Funktion zu überschreiben.
Mit
Diese Definition von
myfunction
überschreibt jede vorherige Definition, da sie zur Analysezeit erfolgt.Während
führt die korrekte Aufgabe aus,
myfunction
nur zu definieren , wann diesecondition
erfüllt ist.quelle
var myFunc = null;
außerhalb einer Schleife oder außerhalb eines if / elseif / else-Blocks zu definieren. Dann können Sie derselben Variablen bedingt verschiedene Funktionen zuweisen. In JS ist es besser, null einen fehlenden Wert zuzuweisen, als undefiniert. Daher sollten Sie myFunction zuerst als null deklarieren und später unter bestimmten Bedingungen zuweisen.Ein wichtiger Grund ist das Hinzufügen einer und nur einer Variablen als "Root" Ihres Namespace ...
oder
Es gibt viele Techniken für den Namespace. Mit der Fülle der verfügbaren JavaScript-Module wird dies immer wichtiger.
Siehe auch Wie deklariere ich einen Namespace in JavaScript?
quelle
Das Heben ist die Aktion des JavaScript-Interpreters, bei der alle Variablen- und Funktionsdeklarationen an den Anfang des aktuellen Bereichs verschoben werden.
Es werden jedoch nur die tatsächlichen Erklärungen gehisst. indem Sie Aufgaben dort belassen, wo sie sind.
Variable
Javascript wird als lose getippte Sprache bezeichnet. Dies bedeutet, dass Javascript-Variablen Werte für jeden Datentyp enthalten können . Javascript sorgt automatisch dafür, dass der Variablentyp basierend auf dem zur Laufzeit angegebenen Wert / Literal geändert wird.
Funktion
Standard Rückgabewert der Funktion ist ‚ undefined ‘, Variable Wert Erklärung Standard auch ‚undefined‘
Funktionserklärung
Funktionsausdruck
Funktion der Variablen zugeordnet Beispiel:
Javascript interpretiert als
Sie können die Funktionsdeklaration und den Ausdruckstest über verschiedene Browser überprüfen
jsperf Test Runner
ES5-Konstruktor-Funktionsklassen : Mit Function.prototype.bind erstellte Funktionsobjekte
JavaScript behandelt Funktionen als erstklassige Objekte. Als Objekt können Sie einer Funktion also Eigenschaften zuweisen.
Mit ES6 eingeführte Pfeilfunktion : Ein Pfeilfunktionsausdruck hat eine kürzere Syntax, eignet sich am besten für Nicht-Methodenfunktionen und kann nicht als Konstruktoren verwendet werden.
quelle
Ich füge meine eigene Antwort hinzu, nur weil alle anderen den Hebeteil gründlich behandelt haben.
Ich habe mich schon lange gefragt, welcher Weg besser ist, und dank http://jsperf.com weiß ich jetzt :)
Funktionsdeklarationen sind schneller, und genau das ist in Webentwicklern wirklich wichtig, oder? ;)
quelle
Eine Funktionsdeklaration und ein einer Variablen zugewiesener Funktionsausdruck verhalten sich nach dem Aufbau der Bindung gleich.
Es gibt jedoch einen Unterschied, wie und wann das Funktionsobjekt tatsächlich seiner Variablen zugeordnet ist. Dieser Unterschied ist auf den Mechanismus zurückzuführen, der in JavaScript als variables Heben bezeichnet wird .
Grundsätzlich werden alle Funktionsdeklarationen und Variablendeklarationen an den Anfang der Funktion gesetzt, in der die Deklaration auftritt (aus diesem Grund haben wir den Funktionsumfang von JavaScript ).
Wenn eine Funktionsdeklaration angehoben wird, "folgt" der Funktionskörper. Wenn der Funktionskörper ausgewertet wird, wird die Variable sofort an ein Funktionsobjekt gebunden.
Wenn eine Variablendeklaration angehoben wird, folgt die Initialisierung nicht , sondern wird "zurückgelassen". Die Variable wird zu
undefined
Beginn des Funktionskörpers initialisiert und zugewiesen Wert an seiner ursprünglichen Stelle im Code. (Tatsächlich wird ihm an jeder Stelle, an der eine Deklaration einer gleichnamigen Variablen erfolgt, ein Wert zugewiesen .)Die Reihenfolge des Hebens ist ebenfalls wichtig: Funktionsdeklarationen haben Vorrang vor Variablendeklarationen mit demselben Namen, und die letzte Funktionsdeklaration hat Vorrang vor früheren Funktionsdeklarationen mit demselben Namen.
Einige Beispiele...
Variable
foo
wird an der Spitze der Funktion gehißt, initialisiertundefined
, so dass!foo
isttrue
, sofoo
zugeordnet ist10
. Dasfoo
Äußere vonbar
spielt keine Rolle und bleibt unberührt.Funktionsdeklarationen haben Vorrang vor Variablendeklarationen, und die letzte Funktionsdeklaration "bleibt".
In diesem Beispiel
a
wird mit dem Funktionsobjekt initialisiert, das sich aus der Auswertung der zweiten Funktionsdeklaration ergibt, und dann zugewiesen4
.Hier wird zuerst die Funktionsdeklaration angehoben, die Variable deklariert und initialisiert
a
. Als nächstes wird diese Variable zugewiesen10
. Mit anderen Worten: Die Zuordnung wird nicht der äußeren Variablen zugewiesena
.quelle
Das erste Beispiel ist eine Funktionsdeklaration:
Das zweite Beispiel ist ein Funktionsausdruck:
Der Hauptunterschied besteht darin, wie sie angehoben (angehoben und deklariert) werden. Im ersten Beispiel wird die gesamte Funktionsdeklaration angehoben. Im zweiten Beispiel wird nur die Variable 'abc' angehoben, ihr Wert (die Funktion) wird undefiniert und die Funktion selbst bleibt an der Position, an der sie deklariert ist.
Einfach gesagt:
Um mehr über dieses Thema zu erfahren, empfehle ich Ihnen dringend diesen Link
quelle
In Bezug auf die Kosten für die Codewartung sind benannte Funktionen vorzuziehen:
Ich vermute, dass weitere PROS für benannte Funktionen folgen. Und was als Vorteil benannter Funktionen aufgeführt ist, ist ein Nachteil für anonyme.
In der Vergangenheit ergaben sich anonyme Funktionen aufgrund der Unfähigkeit von JavaScript als Sprache, Mitglieder mit benannten Funktionen aufzulisten:
quelle
In der Informatik sprechen wir über anonyme Funktionen und benannte Funktionen. Ich denke, der wichtigste Unterschied ist, dass eine anonyme Funktion nicht an einen Namen gebunden ist, daher die anonyme Namensfunktion. In JavaScript ist es ein erstklassiges Objekt, das zur Laufzeit dynamisch deklariert wird.
Für weitere Informationen zu anonymen Funktionen und zur Lambda-Berechnung ist Wikipedia ein guter Anfang ( http://en.wikipedia.org/wiki/Anonymous_function ).
quelle
Ich verwende den variablen Ansatz in meinem Code aus einem ganz bestimmten Grund, dessen Theorie oben abstrakt behandelt wurde, aber ein Beispiel könnte einigen Leuten wie mir mit begrenzten JavaScript-Kenntnissen helfen.
Ich habe Code, den ich mit 160 unabhängig gestalteten Brandings ausführen muss. Der größte Teil des Codes befindet sich in gemeinsam genutzten Dateien, aber markenspezifische Inhalte befinden sich in einer separaten Datei, eine für jedes Branding.
Einige Brandings erfordern bestimmte Funktionen, andere nicht. Manchmal muss ich neue Funktionen hinzufügen, um neue markenspezifische Dinge zu tun. Ich bin froh, die gemeinsam genutzte Codierung ändern zu können, möchte aber nicht alle 160 Sätze von Branding-Dateien ändern müssen.
Mithilfe der Variablensyntax kann ich die Variable (im Wesentlichen einen Funktionszeiger) im gemeinsam genutzten Code deklarieren und entweder eine triviale Stub-Funktion zuweisen oder auf null setzen.
Die ein oder zwei Brandings, die eine bestimmte Implementierung der Funktion benötigen, können dann ihre Version der Funktion definieren und diese der Variablen zuweisen, wenn sie möchten, und der Rest tut nichts. Ich kann eine Nullfunktion testen, bevor ich sie im gemeinsam genutzten Code ausführe.
Aus den obigen Kommentaren geht hervor, dass es möglicherweise auch möglich ist, eine statische Funktion neu zu definieren, aber ich denke, dass die variable Lösung nett und klar ist.
quelle
Gregs Antwort ist gut genug, aber ich möchte noch etwas hinzufügen, das ich gerade gelernt habe, als ich Douglas Crockfords Videos gesehen habe.
Funktionsausdruck:
Funktionsanweisung:
Die Funktionsanweisung ist nur eine Abkürzung für
var
Anweisung mit afunction
Wert.Damit
erweitert sich auf
Was sich weiter ausdehnt zu:
Und beide werden an die Spitze des Codes gehievt.
quelle
Es gibt vier bemerkenswerte Vergleiche zwischen den beiden verschiedenen Funktionsdeklarationen, wie unten aufgeführt.
Folgendes funktioniert, weil
function add()
es auf den nächsten Block beschränkt ist:Das Folgende funktioniert nicht, da die Variable aufgerufen wird, bevor der Variablen ein Funktionswert zugewiesen wird
add
.Der obige Code ist in seiner Funktionalität identisch mit dem folgenden Code. Beachten Sie, dass das explizite Zuweisen
add = undefined
überflüssig ist, da das einfache Ausführenvar add;
genau das gleiche ist wievar add=undefined
.Das Folgende funktioniert nicht, weil das
var add=
diefunction add()
.Der Name einer Funktion
function thefuncname(){}
ist der Funktionsname, wenn sie auf diese Weise deklariert wird.Wenn andernfalls eine Funktion als deklariert ist
function(){}
, ist die Funktion .name die erste Variable, die zum Speichern der Funktion verwendet wird.Wenn für die Funktion keine Variablen festgelegt sind, ist der Funktionsname die leere Zeichenfolge (
""
).Während die Variable, der die Funktion zugewiesen ist, zunächst den Namen festlegt, ändern aufeinanderfolgende Variablen, die der Funktion zugewiesen sind, den Namen nicht.
In Googles V8 und Firefoxs Spidermonkey gibt es möglicherweise einige JIST-Kompilierungsunterschiede von einigen Mikrosekunden, aber letztendlich ist das Ergebnis genau das gleiche. Um dies zu beweisen, untersuchen wir die Effizienz von JSPerf bei Mikrobenchmarks, indem wir die Geschwindigkeit von zwei leeren Codefragmenten vergleichen. Die JSPerf-Tests finden Sie hier . Und die jsben.ch-Tests finden Sie hier . Wie Sie sehen können, gibt es einen spürbaren Unterschied, wenn es keinen geben sollte. Wenn Sie wirklich ein Leistungsfreak wie ich sind, lohnt es sich möglicherweise mehr, die Anzahl der Variablen und Funktionen im Bereich zu reduzieren und insbesondere den Polymorphismus zu eliminieren (z. B. die Verwendung derselben Variablen zum Speichern von zwei verschiedenen Typen).
Wenn Sie das
var
Schlüsselwort verwenden, um eine Variable zu deklarieren, können Sie der Variablen wie folgt einen anderen Wert zuweisen.Wenn wir jedoch die const-Anweisung verwenden, wird die Variablenreferenz unveränderlich. Dies bedeutet, dass wir der Variablen keinen neuen Wert zuweisen können. Beachten Sie jedoch, dass dies den Inhalt der Variablen nicht unveränderlich macht: Wenn Sie dies tun
const arr = []
, können Sie dies dennoch tunarr[10] = "example"
. Nur so etwas zu tunarr = "new value"
oderarr = []
würde einen Fehler auslösen, wie unten gezeigt.Interessanterweise ist, wenn wir die Variable als deklarieren
function funcName(){}
, die Unveränderlichkeit der Variablen dieselbe wie die Deklaration mitvar
.Was ist der "nächste Block"
Der "nächste Block" ist die nächste "Funktion" (einschließlich asynchroner Funktionen, Generatorfunktionen und asynchroner Generatorfunktionen). Interessanterweise
function functionName() {}
verhält sich a jedoch wie einvar functionName = function() {}
Element in einem Block ohne Verschluss gegenüber Elementen außerhalb des Verschlusses. Beobachten.var add=function(){}
function add(){}
if
,else
,for
,while
,try
/catch
/finally
,switch
,do
/while
,with
)var add=function()
function add()
quelle
@EugeneLazutkin gibt ein Beispiel, in dem er eine zugewiesene Funktion benennt, die
shortcut()
als interne Referenz auf sich selbst verwendet werden kann. John Resig gibt ein weiteres Beispiel: Kopieren einer rekursiven Funktion, die einem anderen Objekt in seinem Lernprogramm für Advanced Javascript zugewiesen wurde . Das Zuweisen von Funktionen zu Eigenschaften ist hier nicht unbedingt die Frage. Ich empfehle jedoch, das Lernprogramm aktiv auszuprobieren. Führen Sie den Code aus, indem Sie auf die Schaltfläche in der oberen rechten Ecke klicken, und doppelklicken Sie auf den Code, um ihn nach Ihren Wünschen zu bearbeiten.Beispiele aus dem Tutorial: rekursive Aufrufe in
yell()
:Tests schlagen fehl, wenn das ursprüngliche Ninja-Objekt entfernt wird. (Seite 13)
Wenn Sie die Funktion benennen, die rekursiv aufgerufen wird, bestehen die Tests. (Seite 14)
quelle
Ein weiterer Unterschied, der in den anderen Antworten nicht erwähnt wird, besteht darin, dass Sie die anonyme Funktion verwenden
und benutze das als Konstruktor wie in
dann
one.constructor.name
wird nicht definiert.Function.name
ist nicht Standard, wird jedoch von Firefox, Chrome, anderen von Webkit abgeleiteten Browsern und IE 9+ unterstützt.Mit
Es ist möglich, den Namen des Konstruktors als Zeichenfolge mit abzurufen
two.constructor.name
.quelle
Die erste (Funktion doSomething (x)) sollte Teil einer Objektnotation sein.
Die zweite (
var doSomething = function(x){ alert(x);}
) erstellt einfach eine anonyme Funktion und weist sie einer Variablen zudoSomething
. DoSomething () ruft also die Funktion auf.Vielleicht möchten Sie wissen, was eine Funktionsdeklaration und ein Funktionsausdruck sind sind.
Eine Funktionsdeklaration definiert eine benannte Funktionsvariable, ohne dass eine Variablenzuweisung erforderlich ist. Funktionsdeklarationen treten als eigenständige Konstrukte auf und können nicht in Nichtfunktionsblöcken verschachtelt werden.
In der obigen Bedingung ist der Funktionsname innerhalb seines Bereichs und des Bereichs seines übergeordneten Elements sichtbar (andernfalls wäre er nicht erreichbar).
Und in einem Funktionsausdruck
Ein Funktionsausdruck definiert eine Funktion als Teil einer größeren Ausdruckssyntax (normalerweise eine Variablenzuweisung). Über Funktionsausdrücke definierte Funktionen können benannt oder anonym sein. Funktionsausdrücke sollten nicht mit „Funktion“ beginnen.
quelle
Ich liste die folgenden Unterschiede auf:
Eine Funktionsdeklaration kann an einer beliebigen Stelle im Code platziert werden. Selbst wenn es aufgerufen wird, bevor die Definition im Code angezeigt wird, wird es ausgeführt, wenn die Funktionsdeklaration im Speicher festgeschrieben oder hochgezogen wird, bevor ein anderer Code auf der Seite ausgeführt wird.
Schauen Sie sich die folgende Funktion an:
Dies liegt daran, dass es während der Ausführung wie folgt aussieht:
Ein Funktionsausdruck führt zu einem Fehler, wenn er vor dem Aufruf nicht definiert wurde. Auch hier wird die Funktionsdefinition selbst nicht wie in den Funktionsdeklarationen nach oben verschoben oder in den Speicher übernommen. Aber die Variable, der wir die Funktion zuweisen, wird angehoben und undefiniert wird ihr zugewiesen.
Gleiche Funktion mit Funktionsausdrücken:
Dies liegt daran, dass es während der Ausführung wie folgt aussieht:
Es ist nicht sicher Funktionsdeklarationen in Nicht-Funktionsblöcken wie zu schreiben , wenn , weil sie nicht zugänglich sind.
Der benannte Funktionsausdruck wie der folgende funktioniert möglicherweise nicht in Internet Explorer-Browsern vor Version 9.
quelle
Wenn Sie diese Funktionen zum Erstellen von Objekten verwenden würden, erhalten Sie:
quelle
console.log(objectOne.__proto__);
druckt "functionOne {}" in meiner Konsole. Irgendwelche Ideen, warum dies der Fall sein könnte?In Anbetracht des Arguments "benannte Funktionen werden in Stapelspuren angezeigt" sind moderne JavaScript-Engines tatsächlich in der Lage, anonyme Funktionen darzustellen.
Zum jetzigen Zeitpunkt beziehen sich V8, SpiderMonkey, Chakra und Nitro immer auf benannte Funktionen mit ihren Namen. Sie verweisen fast immer auf eine anonyme Funktion anhand ihrer Kennung, falls vorhanden.
SpiderMonkey kann den Namen einer anonymen Funktion ermitteln, die von einer anderen Funktion zurückgegeben wurde. Der Rest kann nicht.
Wenn Sie wirklich, wirklich wollten, dass Ihre Iterator- und Erfolgsrückrufe in der Ablaufverfolgung angezeigt werden, können Sie diese auch benennen ...
Aber zum größten Teil lohnt es sich nicht, darüber nachzudenken.
Geschirr ( Geige )
V8
Spinnenaffe
Chakra
Nitro
quelle
In JavaScript gibt es zwei Möglichkeiten, Funktionen zu erstellen:
Funktionsdeklaration:
Dies ist sehr einfach, selbsterklärend, wird in vielen Sprachen verwendet und ist in der gesamten C-Sprachfamilie Standard. Wir haben eine Funktion deklariert, die sie definiert und durch Aufrufen ausgeführt hat.
Was Sie wissen sollten, ist, dass Funktionen tatsächlich Objekte in JavaScript sind. intern haben wir ein Objekt für die obige Funktion erstellt und ihm einen Namen namens fn gegeben, oder der Verweis auf das Objekt wird in fn gespeichert. Funktionen sind Objekte in JavaScript. Eine Funktionsinstanz ist eigentlich eine Objektinstanz.
Funktionsausdruck:
JavaScript verfügt über erstklassige Funktionen, dh Sie erstellen eine Funktion und weisen sie einer Variablen zu, genau wie Sie eine Zeichenfolge oder Zahl erstellen und einer Variablen zuweisen. Hier wird die Variable fn einer Funktion zugeordnet. Der Grund für dieses Konzept ist, dass Funktionen Objekte in JavaScript sind. fn zeigt auf die Objektinstanz der obigen Funktion. Wir haben eine Funktion initialisiert und einer Variablen zugewiesen. Die Funktion wird nicht ausgeführt und das Ergebnis nicht zugewiesen.
Referenz: Syntax der JavaScript-Funktionsdeklaration: var fn = function () {} vs function fn () {}
quelle
var fn = function fn() {...}
?Beides sind verschiedene Arten, eine Funktion zu definieren. Der Unterschied besteht darin, wie der Browser sie interpretiert und in einen Ausführungskontext lädt.
Der erste Fall betrifft Funktionsausdrücke, die nur geladen werden, wenn der Interpreter diese Codezeile erreicht. Wenn Sie es also wie folgt tun, erhalten Sie die Fehlermeldung, dass die functionOne keine Funktion ist .
Der Grund ist, dass in der ersten Zeile functionOne kein Wert zugewiesen wird und daher undefiniert ist. Wir versuchen, es als Funktion aufzurufen, und daher wird ein Fehler angezeigt.
In der zweiten Zeile weisen wir functionOne die Referenz einer anonymen Funktion zu.
Der zweite Fall betrifft Funktionsdeklarationen, die geladen werden, bevor Code ausgeführt wird. Wenn Ihnen Folgendes gefällt, wird beim Laden der Deklaration vor der Codeausführung kein Fehler angezeigt.
quelle
Über die Leistung:
In neuen Versionen
V8
wurden mehrere Optimierungen unter der Haube eingeführtSpiderMonkey
.Es gibt jetzt fast keinen Unterschied zwischen Ausdruck und Deklaration.
Der Funktionsausdruck scheint jetzt schneller zu sein .
Chrome 62.0.3202
FireFox 55
Chrome Canary 63.0.3225
Firefox Chrome Canary Chrome
quelle
Sie sind sich mit einigen kleinen Unterschieden ziemlich ähnlich. Die erste ist eine Variable, die einer anonymen Funktion zugewiesen ist (Funktionsdeklaration), und die zweite ist die normale Methode zum Erstellen einer Funktion in JavaScript (anonyme Funktionsdeklaration). Beide haben Verwendung, Nachteile und Vorteile ::
1. Funktionsausdruck
Das Zuweisen einer Variablen zu einer Funktion bedeutet, dass kein Hoisting erforderlich ist, da wir wissen, dass Funktionen in JavaScript Hoist können. Dies bedeutet, dass sie aufgerufen werden können, bevor sie deklariert werden, während Variablen deklariert werden müssen, bevor auf sie zugegriffen werden kann. In diesem Fall können wir dies nicht Greifen Sie auf die Funktion zu, bevor sie deklariert wurde. Es kann auch eine Möglichkeit sein, Ihre Funktionen zu schreiben. Für die Funktionen, die eine andere Funktion zurückgeben, kann diese Art der Deklaration sinnvoll sein. Auch in ECMA6 und höher können Sie dies einer Pfeilfunktion zuweisen, die kann zum Aufrufen anonymer Funktionen verwendet werden. Auch diese Art der Deklaration ist eine bessere Möglichkeit, Konstruktorfunktionen in JavaScript zu erstellen.
2. Funktionserklärung
Dies ist die normale Art, eine Funktion in JavaScript aufzurufen. Diese Funktion kann aufgerufen werden, bevor Sie sie deklarieren, da in JavaScript alle Funktionen angehoben werden. Wenn Sie jedoch "strikt verwenden", wird dies nicht wie erwartet angehoben. Dies ist eine gute Möglichkeit alle normalen Funktionen aufrufen, die nicht groß in Zeilen sind und auch keine Konstruktorfunktion sind.
Wenn Sie weitere Informationen zur Funktionsweise des Hebens in JavaScript benötigen, besuchen Sie den folgenden Link:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
quelle
...also this way of declaring is a better way to create Constructor functions in JavaScript
, bitte erläutern Sie, ich bin neugierig!Dies sind nur zwei Möglichkeiten, Funktionen zu deklarieren. Zweitens können Sie die Funktion vor der Deklaration verwenden.
quelle
new Function()
kann verwendet werden, um den Funktionskörper in einer Zeichenfolge zu übergeben. Und damit können dynamische Funktionen erstellt werden. Übergeben Sie das Skript auch, ohne es auszuführen.quelle