var functionName = function () {} vs function functionName () {}

6872

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?

Richard Garside
quelle
198
permadi.com/tutorial/jsFunc/index.html ist eine sehr gute Seite über Javascript-Funktionen
uzay95
67
In Verbindung steht dieser ausgezeichnete Artikel über benannte Funktionsausdrücke .
Phrogz
12
@CMS verweist auf diesen Artikel: kangax.github.com/nfe/#expr-vs-decl
Upperstage
106
Es gibt zwei Dinge, die Sie beachten müssen: # 1 In JavaScript werden Deklarationen gehisst. Das heißt, das var a = 1; var b = 2;wird var 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.
Xavierm02
65
Übrigens, die richtige Syntax ist mit einem ";" nach der Abtretung und ohne nach der Erklärung. Eg function f(){}vs var f = function(){};.
Xavierm02

Antworten:

5043

Der Unterschied besteht darin, dass functionOnees sich um einen Funktionsausdruck handelt, der nur dann definiert wird, wenn diese Zeile erreicht ist, während functionTwoes 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:

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

Und eine Funktionsdeklaration:

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

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.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError

Greg
quelle
632
@ Greg: Der Unterschied besteht übrigens nicht nur darin, dass sie zu unterschiedlichen Zeiten analysiert werden. Im Wesentlichen handelt es sich bei Ihrer functionOnelediglich um eine Variable, der eine anonyme Funktion zugewiesen ist, während functionTwoes 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.
Jason Bunting
6
@ Jason Bunting .. nicht sicher, was Sie hier bekommen, .toString () scheint im Wesentlichen den gleichen Wert (die Funktionsdefinition) für beide zurückzugeben: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z
124
Es gibt beide verschiedene. Der erste ist ein, function expressionder zweite ist ein function declaration. Sie können mehr über das Thema hier lesen: javascriptweblog.wordpress.com/2010/07/06/…
Michal Kuklis
127
@ Greg Der Teil Ihrer Antwort bezüglich Analysezeit / Laufzeit ist nicht korrekt. In JavaScript werden Funktionsdeklarationen nicht zur Analysezeit, sondern zur Laufzeit definiert. Der Prozess sieht folgendermaßen aus: Der Quellcode wird analysiert -> das JavaScript-Programm wird ausgewertet -> Der globale Ausführungskontext wird initialisiert -> die Instanziierung der Deklarationsbindung wird durchgeführt. Während dieses Vorgangs werden die Funktionsdeklarationen instanziiert (siehe Schritt 5 von Kapitel 10.5 ).
Šime Vidas
102
Die Terminologie für dieses Phänomen ist als Heben bekannt.
Colin Pear
1941

Zuerst möchte ich Greg korrigieren: function abc(){}hat auch einen Gültigkeitsbereich - der Name abcwird in dem Bereich definiert, in dem diese Definition vorkommt. Beispiel:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

Zweitens ist es möglich, beide Stile zu kombinieren:

var xyz = function abc(){};

xyzwird wie gewohnt definiert, abcist 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:

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

Wenn Sie Alias-Funktionen in allen Browsern verwenden möchten, verwenden Sie diese Art von Deklaration:

function abc(){};
var xyz = abc;

In diesem Fall sind beide xyzund abcAliase desselben Objekts:

console.log(xyz === abc); // prints "true"

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

function abc(){};
console.log(abc.name); // prints "abc"

sein Name wird automatisch vergeben. Aber wenn Sie es wie definieren

var abc = function(){};
console.log(abc.name); // prints ""

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:

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

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:

function abc(){}

abc hier ist überall im aktuellen Umfang definiert:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

Es wurde auch durch eine returnAussage gehisst :

// We can call it here
abc(); // Works
return;
function abc(){}

Dies ist ein Funktionsausdruck:

var xyz = function(){};

xyz hier wird ab dem Zeitpunkt der Zuordnung definiert:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

Funktionsdeklaration vs. Funktionsausdruck ist der wahre Grund, warum Greg einen Unterschied zeigt.

Lustige Tatsache:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

Persönlich bevorzuge ich die Deklaration "Funktionsausdruck", da ich auf diese Weise die Sichtbarkeit steuern kann. Wenn ich die Funktion wie definiere

var abc = function(){};

Ich weiß, dass ich die Funktion lokal definiert habe. Wenn ich die Funktion wie definiere

abc = function(){};

Ich weiß, dass ich es global definiert habe, vorausgesetzt, ich habe abcnirgendwo in der Kette der Bereiche definiert. Dieser Definitionsstil ist auch bei Verwendung im Inneren belastbar eval(). Während der Definition

function abc(){};

hä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.

Eugene Lazutkin
quelle
69
Ich beziehe mich auf RoBorg, aber er ist nirgends zu finden. Einfach: RoBorg === Greg. So kann Geschichte im Zeitalter des Internets neu geschrieben werden. ;-)
Eugene Lazutkin
10
var xyz = Funktion abc () {}; console.log (xyz === abc); Alle von mir getesteten Browser (Safari 4, Firefox 3.5.5, Opera 10.10) geben mir "Undefinierte Variable: abc".
NVI
7
Insgesamt denke ich, dass dieser Beitrag die Unterschiede und Vorteile der Verwendung der Funktionsdeklaration gut erklärt. Ich bin damit einverstanden, nicht zuzustimmen, was die Vorteile der Verwendung von Funktionsausdruckzuweisungen für eine Variable angeht, zumal der "Vorteil" ein Befürworter der Deklaration einer globalen Entität zu sein scheint ... und jeder weiß, dass Sie den globalen Namespace nicht überladen sollten , Recht? ;-)
natlee75
83
Ein großer Grund für die Verwendung der benannten Funktion ist, dass Debugger den Namen verwenden können, um Ihren Aufrufstapel oder die Stapelverfolgung zu verstehen. es ist scheiße, wenn man sich den Aufrufstapel ansieht und "anonyme Funktion" 10 Ebenen tief sieht ...
Ziege
3
var abc = function(){}; console.log(abc.name);produziert ""nicht mehr, sondern "abc".
Qwerty
632

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" functionAusdruck (der trotz des Begriffs manchmal Funktionen mit Namen erstellt)

  • Benannter functionAusdruck

  • Accessor 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:

function x() {
    console.log('x');
}

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:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

Bis ES2015, decken die Spezifikation nicht , was ein JavaScript - Engine tun sollten , wenn Sie eine Funktionsdeklaration innerhalb einer Kontrollstruktur wie setzen try, if, switch, whileusw., wie folgt aus :

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

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:

  1. Wenn im Loose-Modus kein Webbrowser verwendet wird, soll die JavaScript-Engine eines tun
  2. Im losen Modus eines Webbrowsers soll die JavaScript-Engine etwas anderes tun
  3. Im strengen Modus (Browser oder nicht) soll die JavaScript-Engine noch etwas anderes 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:

"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)

"Anonymer" functionAusdruck

Die zweite gebräuchliche Form heißt anonymer Funktionsausdruck :

var y = function () {
    console.log('y');
};

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 Sie SetFunctionNamein der Spezifikation.  Es wird überall angezeigt .)

Benannter functionAusdruck

Die dritte Form ist ein benannter Funktionsausdruck ("NFE"):

var z = function w() {
    console.log('zw')
};

Die dadurch erstellte Funktion hat einen Eigennamen ( win 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:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

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:

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 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.definePropertiesund dem weniger bekannten zweiten Argument für erstellen Object.create.

Pfeilfunktionsausdruck (ES2015 +)

ES2015 bringt uns die Pfeil - Funktion . Hier ist ein Beispiel:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Sehen Sie das n => n * 2Ding im map()Anruf versteckt ? Das ist eine Funktion.

Ein paar Dinge über Pfeilfunktionen:

  1. Sie haben keine eigenen this. Stattdessen sie dicht über die thisvon dem Kontext , in dem sie definiert sind. (Sie schließen auch argumentsund, falls relevant,. super) Dies bedeutet, dass das thisin ihnen dasselbe ist wie dasthis in dem sie erstellt wurden, und nicht geändert werden kann.

  2. Wie Sie oben bemerkt haben, verwenden Sie das Schlüsselwort nicht function. stattdessen verwenden Sie =>.

Das n => n * 2obige Beispiel ist eine Form davon. 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

(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 Ausdruck return(wenn Sie einen Wert zurückgeben müssen):

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 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:

var o = {
    foo() {
    }
};

Das fast Äquivalent in ES5 und früher wäre:

var o = {
    foo: function foo() {
    }
};

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, das valueOfmithilfe der Methodensyntax definiert (z. B.) , könnte es verwendet werden super.valueOf(), um den Wert Object.prototype.valueOfabzurufen (bevor Sie vermutlich etwas anderes damit tun), während die ES5-Version dies Object.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.assignals 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 verwendet super).

Konstruktor- und Methodendeklarationen in class(ES2015 +)

ES2015 bringt uns classSyntax, 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 Funktionsdeklarationen aufgeführt: Eine für den Konstruktor, der den Namen erhält Person, und eine für getFullNamedie Funktion, der eine Funktion zugewiesen ist Person.prototype.

TJ Crowder
quelle
3
dann wird der name weinfach ignoriert?
BiAiB
8
@PellePenna: Funktionsnamen sind für viele Dinge nützlich. Die beiden Biggies sind meiner Ansicht nach Rekursion, und der Name der Funktion wird in Aufrufstapeln, Ausnahmespuren und dergleichen angezeigt.
TJ Crowder
4
@ChaimEliyah - "Akzeptieren bedeutet nicht, dass es die beste Antwort ist, es bedeutet nur, dass es für die Person funktioniert hat, die gefragt hat." Quelle
ScrapCode
6
@AR: Ganz richtig. Amüsanterweise steht jedoch direkt darüber: "Die besten Antworten werden zuerst angezeigt, damit sie immer leicht zu finden sind." Da die akzeptierte Antwort auch bei höher bewerteten Antworten zuerst angezeigt wird, kann die Tour etwas widersprüchlich sein. ;-) Auch ein bisschen ungenau, wenn wir durch Stimmen "am besten" bestimmen (was nicht zuverlässig ist, es ist genau das, was wir haben), werden "beste" Antworten nur dann zuerst angezeigt, wenn Sie die Registerkarte "Stimmen" verwenden - Andernfalls sind die ersten Antworten die aktiven oder die ältesten.
TJ Crowder
1
@TJCrowder: Einverstanden. 'nach Datum geordnet' ist manchmal ärgerlich.
ScrapCode
143

Wenn Sie über den globalen Kontext sprechen, erstellen sowohl die varAnweisung als auch a FunctionDeclarationam 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 varinitialisiert undefinedwerden und diejenigen, die von den FunctionDeclaration's verwendet werden, seit diesem Moment verfügbar sind, zum Beispiel:

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

Die Zuordnung der bar FunctionExpressionerfolgt bis zur Laufzeit.

Eine von a erstellte globale Eigenschaft FunctionDeclarationkann wie ein variabler Wert problemlos überschrieben werden, z. B.:

 function test () {}
 test = null;

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 das varSchlüsselwort zu verwenden.

Mit einer Aufgabe, ohne die varWenn 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 FunctionDeclarationnicht überschrieben werden konnten, was nicht der Fall ist.

CMS
quelle
Ich wusste nicht, dass Funktionen in JavaScript überschrieben werden können! Auch diese Analyse ist das große Verkaufsargument für mich. Ich muss wohl beobachten, wie ich Funktionen erstelle.
Xeoncross
2
+0 auf den Artikel "Names Funktionsausdrücke entmystifiziert", da es 404ing ist. Möglicher Spiegel?: Kangax.github.com/nfe
Mr_Chimp
@CMS Schön. Denken Sie daran, dass ich das Original nie gesehen habe, sodass ich nicht weiß, ob es sich um einen Spiegel oder nur einen anderen Artikel mit demselben Titel handelt!
Mr_Chimp
@ Mr_Chimp Ich bin mir ziemlich sicher, dass es so ist. Thewaybackmachine sagt, dass es beim Crawlen eine 302 hat und die Umleitung zu dem von Ihnen angegebenen Link erfolgte.
John
123

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 fooLaufzeit der Variablen zugewiesen wird. Im zweiten Fall wird die Funktion zur Analysezeit dieser Kennung zugewiesen foo.

Weitere technische Informationen

JavaScript bietet drei Möglichkeiten zum Definieren von Funktionen.

  1. Ihr erstes Snippet zeigt einen Funktionsausdruck . Dies beinhaltet die Verwendung des Operators "function" zum Erstellen einer Funktion - das Ergebnis dieses Operators kann in einer beliebigen Variablen- oder Objekteigenschaft gespeichert werden. Der Funktionsausdruck ist auf diese Weise mächtig. Der Funktionsausdruck wird oft als "anonyme Funktion" bezeichnet, da er keinen Namen haben muss.
  2. Ihr zweites Beispiel ist eine Funktionsdeklaration . Dies verwendet die Anweisung "function" , um eine Funktion zu erstellen. Die Funktion wird zur Analysezeit zur Verfügung gestellt und kann überall in diesem Bereich aufgerufen werden. Sie können es später noch in einer Variablen- oder Objekteigenschaft speichern.
  3. Die dritte Möglichkeit, eine Funktion zu definieren, ist der Konstruktor "Function ()" , der in Ihrem ursprünglichen Beitrag nicht angezeigt wird. Es wird nicht empfohlen, dies zu verwenden, da es genauso funktioniert wie das eval(), was seine Probleme hat.
thomasrutter
quelle
103

Eine bessere Erklärung für Gregs Antwort

functionTwo();
function functionTwo() {
}

Warum kein Fehler? Uns wurde immer beigebracht, dass Ausdrücke von oben nach unten ausgeführt werden (??)

Weil:

Funktionsdeklarationen und Variablendeklarationen werden hoistedvom JavaScript-Interpreter immer unsichtbar an den Anfang ihres enthaltenen Bereichs verschoben ( ). Funktionsparameter und sprachdefinierte Namen sind offensichtlich bereits vorhanden. Ben Kirsche

Dies bedeutet, dass der Code wie folgt lautet:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

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 :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
suhailvs
quelle
Hallo, danke für die klaren Informationen zum Funktionsthema. Nun ist meine Frage, welche die erste Deklaration in der Deklarationshierarchie sein wird, ob Variablendeklaration (functionOne) oder Funktionsdeklaration (functionTwo)?
Sharathi RB
91

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:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

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.)

Sean McMillan
quelle
4
yuiblog.com/blog/2007/06/12/module-pattern ist, soweit ich das beurteilen kann, die ursprüngliche Referenz für das Modulmuster . (Obwohl dieser Artikel die var foo = function(){...}Syntax auch für private Variablen verwendet.
Sean McMillan
Dies ist in einigen älteren IE-Versionen nicht ganz der Fall. ( function window.onload() {}war eine Sache.)
Ry-
77

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

if (condition){
    function myfunction(){
        // Some code
    }
}

Diese Definition von myfunctionüberschreibt jede vorherige Definition, da sie zur Analysezeit erfolgt.

Während

if (condition){
    var myfunction = function (){
        // Some code
    }
}

führt die korrekte Aufgabe aus, myfunctionnur zu definieren , wann diese conditionerfüllt ist.

Mbengue Assane
quelle
1
Dieses Beispiel ist gut und nahezu perfekt, könnte aber verbessert werden. Das bessere Beispiel wäre, 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.
Alexander Mills
62

Ein wichtiger Grund ist das Hinzufügen einer und nur einer Variablen als "Root" Ihres Namespace ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

oder

var MyNamespace = {
  foo: function() {
  },
  ...
}

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?

rauben
quelle
3
Es scheint , diese Antwort auf diese Frage aus einer anderen Frage verschmolzen wurde, und die Formulierung könnte scheint ein klein wenig in keinem Zusammenhang mit zu dieser Frage. Würden Sie erwägen, die Antwort so zu bearbeiten, dass sie spezifischer auf diese Frage ausgerichtet zu sein scheint? (um es noch einmal zu wiederholen; das ist überhaupt nicht deine Schuld ... nur ein Nebeneffekt einer zusammengeführten Frage). Sie können es auch löschen, und ich denke, Sie würden Ihren Ruf behalten. Oder du kannst es verlassen; da es alt ist, kann es keinen großen Unterschied machen.
Andrew Barber
55

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.

  • Innerhalb der Seite deklarierte Variablen / Funktionen sind global und können überall auf dieser Seite zugreifen.
  • Innerhalb der Funktion deklarierte Variablen / Funktionen haben einen lokalen Gültigkeitsbereich. bedeutet, dass sie innerhalb des Funktionskörpers (Gültigkeitsbereich) verfügbar sind / darauf zugegriffen werden kann, dass sie außerhalb des Funktionskörpers nicht verfügbar 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.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777 Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

Funktion

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • Innerhalb der Seite deklarierte Funktionen werden mit globalem Zugriff an den oberen Rand der Seite gehoben.
  • Funktionen, die im Funktionsblock deklariert sind, werden an die Oberseite des Blocks gehoben.
  • Standard Rückgabewert der Funktion ist ‚ undefined ‘, Variable Wert Erklärung Standard auch ‚undefined‘

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

Funktionserklärung

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

Funktionsausdruck

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

Funktion der Variablen zugeordnet Beispiel:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

Javascript interpretiert als

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

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.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

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.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
Yash
quelle
3
ahm, deine antwort ... ist es nicht mehrdeutig? Gut geschrieben, also +1 für Ausgaben und zu viele Informationen.
Dänisch
40

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 :)

Geben Sie hier die Bildbeschreibung ein

Funktionsdeklarationen sind schneller, und genau das ist in Webentwicklern wirklich wichtig, oder? ;)

Leon Gaban
quelle
8
Ich würde sagen, dass die Wartbarkeit der wichtigste Aspekt des meisten Codes ist. Die Leistung ist wichtig, aber in den meisten Fällen ist E / A wahrscheinlich ein größerer Engpass als die Art und Weise, wie Sie Ihre Funktionen definieren. Es gibt jedoch einige Probleme, bei denen Sie jede Leistung benötigen, die Sie erhalten können, und dies ist in diesen Fällen nützlich. Es ist auch gut, hier eine Antwort zu haben, die einen genau definierten Teil der Frage klar beantwortet.
Richard Garside
3
Nun, ich fand es anders herum mit Firefox. jsperf.com/sandytest
Sandeep Nayak
Nur ein Update, da ich jetzt in JavaScript einen voll funktionsfähigen Programmierstil habe, verwende ich niemals Deklarationen, sondern nur Funktionsausdrücke, damit ich meine Funktionen anhand ihrer Variablennamen verketten und aufrufen kann. Check out RamdaJS ...
Leon Gaban
1
@SandeepNayak Ich habe gerade Ihren eigenen Test in Firefox 50.0.0 / Windows 7 0.0.0 ausgeführt, und es ist tatsächlich der gleiche Weg wie bei Leon. Wenn Ihr Test also korrekt ist, würde ich zu dem Schluss kommen, dass die Tests von jsperf keine Richtwerte sind und alles von Ihrem Browser und / oder der Betriebssystemversion oder vom jeweiligen Status des aktuellen Computers in diesem bestimmten Moment abhängt.
Ocramot
33

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 undefinedBeginn 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...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

Variable foowird an der Spitze der Funktion gehißt, initialisiert undefined, so dass !fooist true, so foozugeordnet ist 10. Das fooÄußere vonbar spielt keine Rolle und bleibt unberührt.

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

Funktionsdeklarationen haben Vorrang vor Variablendeklarationen, und die letzte Funktionsdeklaration "bleibt".

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

In diesem Beispiel awird mit dem Funktionsobjekt initialisiert, das sich aus der Auswertung der zweiten Funktionsdeklaration ergibt, und dann zugewiesen 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Hier wird zuerst die Funktionsdeklaration angehoben, die Variable deklariert und initialisiert a. Als nächstes wird diese Variable zugewiesen 10. Mit anderen Worten: Die Zuordnung wird nicht der äußeren Variablen zugewiesen a.

Eljenso
quelle
3
Sie haben eine etwas seltsame Art, die schließenden Klammern zu platzieren. Sind Sie ein Python-Codierer? Es sieht so aus, als würden Sie versuchen, Javascript wie Python aussehen zu lassen. Ich fürchte, es ist verwirrend für andere Menschen. Wenn ich Ihren JavaScript-Code pflegen müsste, würde ich Ihren Code zuerst durch einen automatischen Pretty-Drucker lassen.
Nalply
1
Ausgezeichnete Post. Eine "selbstausführende Funktion" oder ein "sofort aufgerufener Funktionsausdruck" sollte leicht zu erkennen sein und seine Stilpräferenz sollte seinen Beitrag nicht beeinträchtigen - was genau ist und das "Heben" perfekt zusammenfasst. +1
Ricalsin
32

Das erste Beispiel ist eine Funktionsdeklaration:

function abc(){}

Das zweite Beispiel ist ein Funktionsausdruck:

var abc = function() {};

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:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Um mehr über dieses Thema zu erfahren, empfehle ich Ihnen dringend diesen Link

sla55er
quelle
1
Ihr Beispiel entspricht in etwa der Top-Antwort
GôTô
Der Hauptgrund für die Veröffentlichung dieser Antwort war die Bereitstellung des Links unten. Dies war das Stück, das mir fehlte, um die obige Frage vollständig zu verstehen.
Sla55er
1
Es ist sehr cool, dass Sie den Link teilen wollten. Links zu zusätzlichen Informationen in SO sollten jedoch nur ein Kommentar zur Frage oder zu Ihrer bevorzugten Antwort sein. Es ist sehr suboptimal, eine lange, komplizierte Seite wie diese mit wiederholten Informationen zu überladen, um am Ende einen einzigen nützlichen Link hinzuzufügen. Nein, Sie erhalten keine Wiederholungspunkte für die Bereitstellung des Links, aber Sie helfen der Community.
XML
30

In Bezug auf die Kosten für die Codewartung sind benannte Funktionen vorzuziehen:

  • Unabhängig von dem Ort, an dem sie deklariert sind (aber immer noch durch den Umfang begrenzt).
  • Widerstandsfähiger gegen Fehler wie bedingte Initialisierung (Sie können diese auch überschreiben, wenn Sie dies möchten).
  • Der Code wird lesbarer, indem lokale Funktionen getrennt von der Bereichsfunktionalität zugewiesen werden. Normalerweise steht im Umfang die Funktionalität an erster Stelle, gefolgt von Deklarationen lokaler Funktionen.
  • In einem Debugger sehen Sie deutlich den Funktionsnamen auf dem Aufrufstapel anstelle einer "anonymen / ausgewerteten" Funktion.

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:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
Sasha Firsov
quelle
2
Es gibt den Test zu bestätigen: blog.firsov.net/2010/01/… JS Leistungstest - Umfang und benannte Funktionen - Analytics
Sasha Firsov
25

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 ).

Kafka
quelle
Ab ES2015 (sechseinhalb Jahre nach Veröffentlichung Ihrer Antwort) sind beide Funktionen in der Frage benannt.
TJ Crowder
25

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.

Herc
quelle
25

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:

var foo = function foo() {};

Funktionsanweisung:

function foo() {};

Die Funktionsanweisung ist nur eine Abkürzung für varAnweisung mit afunction Wert.

Damit

function foo() {};

erweitert sich auf

var foo = function foo() {};

Was sich weiter ausdehnt zu:

var foo = undefined;
foo = function foo() {};

Und beide werden an die Spitze des Codes gehievt.

Screenshot vom Video

Rohan
quelle
7
Entschuldigung, aber das ist falsch - ich weiß nicht, was Crockford auf dieser Folie zu sagen versucht. Sowohl Funktions- als auch Variablendeklarationen werden immer an die Spitze ihres Gültigkeitsbereichs gehoben. Der Unterschied besteht darin, dass Variablenzuweisungen (unabhängig davon, ob Sie sie mit einem String, einem Booleschen Wert oder einer Funktion zuweisen) nicht nach oben gehoben werden, während dies bei Funktionskörpern (mithilfe der Funktionsdeklaration) der Fall ist.
Thomas Heymann
Schauen Sie sich diese Codebeispiele an: gist.github.com/cyberthom/36603fbc20de8e04fd09
Thomas Heymann
24

Es gibt vier bemerkenswerte Vergleiche zwischen den beiden verschiedenen Funktionsdeklarationen, wie unten aufgeführt.

  1. Verfügbarkeit (Umfang) der Funktion

Folgendes funktioniert, weil function add()es auf den nächsten Block beschränkt ist:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Das Folgende funktioniert nicht, da die Variable aufgerufen wird, bevor der Variablen ein Funktionswert zugewiesen wird add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

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ühren var add;genau das gleiche ist wie var add=undefined.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

Das Folgende funktioniert nicht, weil das var add=die function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

  1. (Funktion) .name

Der Name einer Funktion function thefuncname(){}ist der Funktionsname, wenn sie auf diese Weise deklariert wird.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

Wenn andernfalls eine Funktion als deklariert ist function(){}, ist die Funktion .name die erste Variable, die zum Speichern der Funktion verwendet wird.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

Wenn für die Funktion keine Variablen festgelegt sind, ist der Funktionsname die leere Zeichenfolge ( "").

console.log((function(){}).name === "");

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.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Performance

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).

  1. Variable Mutabilität

Wenn Sie das varSchlüsselwort verwenden, um eine Variable zu deklarieren, können Sie der Variablen wie folgt einen anderen Wert zuweisen.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

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 tun arr[10] = "example". Nur so etwas zu tun arr = "new value"oder arr = []würde einen Fehler auslösen, wie unten gezeigt.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Interessanterweise ist, wenn wir die Variable als deklarieren function funcName(){}, die Unveränderlichkeit der Variablen dieselbe wie die Deklaration mit var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

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 ein var functionName = function() {}Element in einem Block ohne Verschluss gegenüber Elementen außerhalb des Verschlusses. Beobachten.

  • Normal var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Normal function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • Funktion

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Anweisung (wie if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Pfeilfunktion mit var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Pfeilfunktion mit function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();

Jack Giffin
quelle
Dies verdient die akzeptierte und am meisten befürwortete Antwort
Aaron John Sabu
18

@EugeneLazutkin gibt ein Beispiel, in dem er eine zugewiesene Funktion benennt, dieshortcut() 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)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

Wenn Sie die Funktion benennen, die rekursiv aufgerufen wird, bestehen die Tests. (Seite 14)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
Joel Purra
quelle
17

Ein weiterer Unterschied, der in den anderen Antworten nicht erwähnt wird, besteht darin, dass Sie die anonyme Funktion verwenden

var functionOne = function() {
    // Some code
};

und benutze das als Konstruktor wie in

var one = new functionOne();

dann one.constructor.namewird nicht definiert.Function.nameist nicht Standard, wird jedoch von Firefox, Chrome, anderen von Webkit abgeleiteten Browsern und IE 9+ unterstützt.

Mit

function functionTwo() {
    // Some code
}
two = new functionTwo();

Es ist möglich, den Namen des Konstruktors als Zeichenfolge mit abzurufen two.constructor.name.

Ingo Kegel
quelle
Der Name wird im ersten Fall nicht definiert, da es sich um eine anonyme Funktion handelt, die einer Variablen zugewiesen ist. Ich denke, das Wort anonym wurde für Dinge erfunden, deren Name nicht definiert ist :)
Om Shankar
In diesem Beispiel wird die zwei = neu eine globale Funktion, weil keine var
Waqas Tahir
16

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 zu doSomething. 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.

function foo() {
    return 3;
}

ECMA 5 (13.0) definiert die Syntax als
Funktionskennung (FormalParameterList opt ) {FunctionBody}

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.

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0) definiert die Syntax als
Funktion Identifier opt (FormalParameterList opt ) {FunctionBody}

NullPoiиteя
quelle
16

Ich liste die folgenden Unterschiede auf:

  1. 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:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    Dies liegt daran, dass es während der Ausführung wie folgt aussieht:

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

    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:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    Dies liegt daran, dass es während der Ausführung wie folgt aussieht:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. Es ist nicht sicher Funktionsdeklarationen in Nicht-Funktionsblöcken wie zu schreiben , wenn , weil sie nicht zugänglich sind.

    if (test) {
        function x() { doSomething(); }
    }
  3. Der benannte Funktionsausdruck wie der folgende funktioniert möglicherweise nicht in Internet Explorer-Browsern vor Version 9.

    var today = function today() {return new Date()}
varna
quelle
1
@Arjun Was ist das Problem, wenn eine Frage Jahre zuvor gestellt wurde? Eine Antwort kommt nicht nur dem OP zugute, sondern möglicherweise allen SO-Benutzern, unabhängig davon, wann die Frage gestellt wurde. Und was ist falsch daran, Fragen zu beantworten, die bereits akzeptiert wurden?
SantiBailors
1
@Arjun du musst verstehen, alte Fragen zu beantworten ist nicht schlecht. Wenn es so wäre, hätte SO eine solche Barriere gehabt. Stellen Sie sich vor, es gibt eine Änderung in der API (wenn auch nicht im Kontext dieser Frage) und jemand entdeckt sie und gibt eine Antwort mit der neuen API. Sollte das nicht erlaubt sein? Solange die Antwort keinen Sinn ergibt und nicht hierher gehört, wird sie automatisch herabgestuft und entfernt. Sie müssen sich nicht darum kümmern !!!!
Sudhansu Choudhary
15

Wenn Sie diese Funktionen zum Erstellen von Objekten verwenden würden, erhalten Sie:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
Pawel Furmaniak
quelle
Ich kann das scheinbar nicht reproduzieren. console.log(objectOne.__proto__);druckt "functionOne {}" in meiner Konsole. Irgendwelche Ideen, warum dies der Fall sein könnte?
Mike
Ich kann es anscheinend auch nicht reproduzieren.
Daremkd
1
Dies ist eine Funktion Ihres Debuggers (um die "Klasse" des protokollierten Objekts anzuzeigen), und die meisten können heutzutage sogar für anonyme Funktionsausdrücke einen Namen ableiten. Übrigens sollten Sie klarstellen, dass es keinen funktionalen Unterschied zwischen den beiden Instanzen gibt.
Bergi
12

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 ...

[].forEach(function iterator() {});

Aber zum größten Teil lohnt es sich nicht, darüber nachzudenken.

Geschirr ( Geige )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

Spinnenaffe

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

Chakra

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

Nitro

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
Jackson
quelle
12

In JavaScript gibt es zwei Möglichkeiten, Funktionen zu erstellen:

  1. Funktionsdeklaration:

    function fn(){
      console.log("Hello");
    }
    fn();

    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.

  2. Funktionsausdruck:

    var fn=function(){
      console.log("Hello");
    }
    fn();

    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 () {}

Anoop Rai
quelle
1
Was ist mit der dritten Option var fn = function fn() {...}?
Chharvey
Hallo Chharvey, ich bin mir nicht sicher über deine Frage, ich denke du sprichst über den Funktionsausdruck, den ich bereits erwähnt habe. Wenn es dennoch Verwirrung gibt, seien Sie einfach ausführlicher.
Anoop Rai
Ja, ich habe nach einem benannten Funktionsausdruck gefragt . Es ähnelt Ihrer Option 2, außer dass die Funktion eine Kennung hat. Normalerweise ist dieser Bezeichner derselbe wie die Variable, der er zugewiesen wird, aber das ist nicht immer der Fall.
Chharvey
1
Ja Der benannte Funktionsausdruck ähnelt meiner Option 2. Eine Kennung ist nicht zwingend erforderlich, da sie nicht verwendet wird. Wann immer Sie den Funktionsausdruck ausführen, verwenden Sie die Variable, die das Funktionsobjekt enthält. Kennung hat keinen Zweck.
Anoop Rai
11

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 .

functionOne();
var functionOne = function() {
    // Some code
};

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.

functionOne();
function functionOne() {
   // Some code
}
Nitin9791
quelle
11

Über die Leistung:

In neuen Versionen V8wurden mehrere Optimierungen unter der Haube eingeführt SpiderMonkey.

Es gibt jetzt fast keinen Unterschied zwischen Ausdruck und Deklaration.
Der Funktionsausdruck scheint jetzt schneller zu sein .

Chrome 62.0.3202 Chrome-Test

FireFox 55 Firefox-Test

Chrome Canary 63.0.3225 Chrome Canary Test


AnonymousFunktionsausdrücke scheinen eine bessere Leistung gegenüber NamedFunktionsausdrücken zu haben .


Firefox Chrome Canary ChromeFirefox namens_anonymous Chrome Kanarienvogel namens_anonymous Chrome named_anonymous

Panos Kal.
quelle
1
Ja, dieser Unterschied ist so unbedeutend , dass hoffentlich Devs beschäftigt sich mit dem Ansatz besser verwaltbar für ihre spezifischen Bedürfnisse ist , anstatt die man vielleicht schneller sein (Sie werden verschiedene jsperf Ergebnisse auf jedem Versuch, je nachdem , was der Browser tat - Die meisten Javascript-Aufgaben müssen sich nicht mit Mikrooptimierungen in diesem Maße befassen.
Squidbe
@squidbe Es gibt keinen Unterschied. Schauen Sie hier: jsperf.com/empty-tests-performance
Jack Giffin
10

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

var functionOne = function() {
    // Some code
};

Ein Funktionsausdruck definiert eine Funktion als Teil einer größeren Ausdruckssyntax (normalerweise eine Variablenzuweisung). Über Funktionen definierte Funktionen Ausdrücke können benannt oder anonym sein. Funktionsausdrücke dürfen nicht mit „Funktion“ beginnen (daher die Klammern um das selbstaufrufende Beispiel unten).

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

function functionTwo() {
    // Some code
}

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. Es ist hilfreich, sie als Geschwister variabler Deklarationen zu betrachten. So wie Variablendeklarationen mit „var“ beginnen müssen, müssen Funktionsdeklarationen mit „function“ beginnen.

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

Alireza
quelle
1
...also this way of declaring is a better way to create Constructor functions in JavaScript, bitte erläutern Sie, ich bin neugierig!
Karl Morrison
Ein Grund dafür ist, dass alle in JavaScript integrierten Konstruktorfunktionen wie diese Funktion Number () {[nativer Code]} erstellt wurden und Sie nicht mit integrierten Funktionen verwechselt werden sollten. In diesem Fall ist es auch sicherer, später darauf zu verweisen, und Sie beenden ordentlicher Code, aber ohne Heben ...
Alireza
8

Dies sind nur zwei Möglichkeiten, Funktionen zu deklarieren. Zweitens können Sie die Funktion vor der Deklaration verwenden.

Tao
quelle
7

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.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()
SuperNova
quelle
Dies ist zwar gut und wahr, aber wie genau hängt dies allein mit der gestellten Frage zusammen?
Jack Giffin