javascript parameter var functionName=Funktion(){} vs Funktion Funktionsname(){}




js function vs function (24)

Ich habe vor kurzem damit begonnen, den JavaScript-Code eines anderen Benutzers zu pflegen. Ich korrigiere Fehler, füge Funktionen hinzu und versuche, den Code aufzuräumen und ihn einheitlicher zu gestalten.

Der bisherige Entwickler verwendet zwei Möglichkeiten, Funktionen zu deklarieren, und ich kann nicht herausfinden, ob es einen Grund 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 zwei verschiedenen Methoden und welche Vor- und Nachteile haben beide? Gibt es etwas, das mit einer Methode möglich ist, mit der anderen Methode nicht?


Ich füge meine eigene Antwort hinzu, nur weil alle anderen den Hebeteil gründlich abgedeckt haben.

Ich habe mich schon gefragt, welcher Weg seit langem besser ist, und dank http://jsperf.com weiß ich es jetzt :)

Funktionsdeklarationen sind schneller, und das ist es, worauf es bei Web-Entwicklern wirklich ankommt? ;)


Ü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

FireFox 55

Chrome Canary 63.0.3225


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


Firefox Chrome Canary Chrom


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 als definiert deklariert und durch Aufruf ausgeführt.

    Sie sollten wissen, dass Funktionen eigentlich Objekte in JavaScript sind. intern haben wir ein Objekt für die obige Funktion erstellt und ihm einen Namen namens fn gegeben oder die Referenz auf das Objekt wird in fn gespeichert. Funktionen sind Objekte in JavaScript. Eine Instanz einer Funktion 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, genauso wie Sie einen String oder eine Zahl erstellen und einer Variablen zuweisen. Hier wird die Variable fn einer Funktion zugewiesen. 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 zugewiesen.

Referenz: JavaScript-Funktionsdeklarationssyntax: var fn = function () {} vs 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 dies wie folgt tun, erhalten Sie eine Fehlermeldung, dass das 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 zu bezeichnen, und daher erhalten wir einen Fehler.

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 Sie also Folgendes mögen, erhalten Sie keine Fehler, wenn die Deklaration vor der Codeausführung geladen wird.

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

Zuerst möchte ich Greg korrigieren: function abc(){} hat ebenfalls Gültigkeitsbereich - der Name abc ist in dem Gültigkeitsbereich 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(){};

xyz wird wie üblich definiert, abc ist in allen Browsern undefiniert, aber Internet Explorer - 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 Funktionen in allen Browsern als Alias ​​verwenden möchten, verwenden Sie diese Art der Deklaration:

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

In diesem Fall sind sowohl xyz als auch abc Aliase desselben Objekts:

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

Ein zwingender Grund für die Verwendung des kombinierten Stils ist das "name" -Attribut von Funktionsobjekten ( nicht von Internet Explorer unterstützt ). Grundsätzlich bei der Definition einer Funktion wie

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

Der Name wird automatisch vergeben. Aber wenn du es gerne definierst

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 ist die Verwendung eines kurzen internen Namens, um auf sich selbst zu verweisen, während für externe Benutzer ein langer, nicht in Konflikt stehender Name angegeben wird:

// 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 von arguments.callee , die noch relativ lang ist und im strikten Modus nicht unterstützt wird.)

Im Grunde 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 return Anweisung gehisst:

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

Dies ist ein Funktionsausdruck:

var xyz = function(){};

xyz hier vom Zuweisungspunkt aus 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.

Spaß Fakt:

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

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

var abc = function(){};

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

abc = function(){};

Ich weiß, dass ich es global definiert habe, vorausgesetzt, ich habe abc nirgendwo in der Kette der Gültigkeitsbereiche definiert. Dieser Definitionsstil ist auch in eval() verwendbar. Während der Definition

function abc(){};

Das hängt vom Kontext ab und lässt Sie vermuten, wo es tatsächlich definiert ist, insbesondere im Fall von eval() Die Antwort lautet: Es hängt vom Browser ab.


Moderne JavaScript-Engines sind angesichts des Arguments "benannte Funktionen werden in Stapelverfolgungen sichtbar" durchaus in der Lage, anonyme Funktionen darzustellen.

Zum jetzigen Zeitpunkt beziehen sich V8, SpiderMonkey, Chakra und Nitro immer auf benannte Funktionen. Sie beziehen sich 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 wird. Der Rest kann nicht.

Wenn Sie wirklich wollten, dass Ihre Iterator- und Erfolgs-Callbacks in der Ablaufverfolgung angezeigt werden, könnten Sie diese auch nennen ...

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

Aber zum größten Teil ist es nicht wert, betont zu werden.

Geschirr ( Fiddle )

'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:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


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


func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


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


func.name: l
Trace:
[email protected]://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:
[email protected]://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
[email protected]://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:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

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

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

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

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

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

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

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

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

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

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

func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

In Bezug auf die Codewartungskosten sind benannte Funktionen vorzuziehen:

  • Unabhängig von dem Ort, an dem sie deklariert werden (jedoch nach Umfang begrenzt).
  • Resistenter gegen Fehler wie die bedingte Initialisierung (Sie können sie immer noch überschreiben, wenn Sie möchten).
  • Der Code wird lesbarer, indem lokale Funktionen getrennt von der Bereichsfunktion zugewiesen werden. Normalerweise geht die Funktionalität in diesem Bereich an erster Stelle, gefolgt von Deklarationen lokaler Funktionen.
  • In einem Debugger sehen Sie eindeutig den Funktionsnamen auf der Aufrufliste und nicht die Funktion "anonym / ausgewertet".

Ich vermute, dass weitere PROS für benannte Funktionen folgen. Was als Vorteil benannter Funktionen aufgeführt wird, ist für anonyme Funktionen ein Nachteil.

In der Vergangenheit waren anonyme Funktionen auf die Unfähigkeit von JavaScript als Sprache zurückzuführen, Mitglieder mit benannten Funktionen aufzulisten:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}

Ein wichtiger Grund ist, eine und nur eine Variable als "Root" Ihres Namespaces hinzuzufügen ...

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

}

oder

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

Es gibt viele Techniken zum Namensraum. Mit der Fülle an verfügbaren JavaScript-Modulen wird dies immer wichtiger.

Siehe auch Wie deklariere ich einen Namespace in JavaScript?


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

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

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

    return exports;
})();

Bei diesem Muster verwenden alle öffentlichen Funktionen die Zuweisung, während Ihre privaten Funktionen die Deklaration verwenden.

(Beachten Sie auch, dass die Zuweisung nach der Anweisung ein Semikolon erfordern sollte, während die Deklaration dies verbietet.)


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


new Function()kann verwendet werden, um den Rumpf der Funktion in einem String zu übergeben. Und damit können dynamische Funktionen erstellt werden. Das Skript auch übergeben, ohne das Skript auszuführen.

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

secondFunction()

Hier ist der Überblick über die Standardformulare, die Funktionen erstellen: (Ursprünglich für eine andere Frage geschrieben, aber angepasst, nachdem sie in die kanonische Frage verschoben wurde.)

Bedingungen:

Die Schnellliste:

  • Funktionserklärung

  • "Anonyme" function Expression (die trotz des Begriffs manchmal Funktionen mit Namen erstellt)

  • Benannte function Ausdruck

  • Accessor-Funktionsinitialisierer (ES5 +)

  • Arrow Funktionsausdruck (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 der class (ES2015 +)

Funktionserklärung

Das erste Formular ist eine Funktionsdeklaration , die folgendermaßen aussieht:

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

Eine Funktionsdeklaration ist eine Deklaration . Es ist keine Aussage oder ein Ausdruck. Als solches folgen Sie nicht mit einem ; (obwohl dies harmlos ist).

Eine Funktionsdeklaration wird verarbeitet, wenn die Ausführung in den Kontext eintritt, in dem sie erscheint, bevor ein Schritt-für-Schritt-Code ausgeführt wird. Die von ihr erstellte Funktion erhält einen eigenen Namen ( x im obigen Beispiel), und dieser Name wird in den Bereich gesetzt, 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 deckte die Spezifikation nicht ab, was eine JavaScript-Engine tun soll, wenn Sie eine Funktionsdeklaration in eine Kontrollstruktur wie try , if , switch , while usw. einfügen:

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 vor ES2015 nicht angegeben wurde , war dies eine zulässige Erweiterung zur Unterstützung von Funktionsdeklarationen in Blöcken. Leider (und unausweichlich) haben verschiedene Motoren unterschiedliche Dinge getan.

Ab ES2015 gibt die Spezifikation an, was zu tun ist. In der Tat gibt es drei verschiedene Dinge zu tun:

  1. Wenn im lockeren Modus kein Webbrowser vorhanden ist, soll die JavaScript-Engine eine Sache tun
  2. Im lockeren Modus eines Webbrowsers soll die JavaScript-Engine etwas anderes tun
  3. Im strikten Modus (Browser oder nicht) soll die JavaScript-Engine noch etwas anderes tun

Die Regeln für die losen Modi sind schwierig, aber im strikten Modus sind Funktionsdeklarationen in Blöcken einfach: Sie sind lokal für den Block (sie haben Blockbereich , der in ES2015 ebenfalls neu ist) und werden nach oben gehoben des Blocks. So:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

"Anonyme" function Ausdruck

Die zweite allgemeine Form wird als anonymer Funktionsausdruck bezeichnet :

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 erstellte Funktion keinen Namen (sie ist anonym). In ES2015 erhält die Funktion nach Möglichkeit einen Namen, 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. (Für Details zum Zeitpunkt und zu den Regeln suchen SetFunctionName in der Spezifikation nach SetFunctionName - es wird überall angezeigt.)

Benannte function Ausdruck

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

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

Die Funktion, die erstellt wird, hat einen eigenen Namen (in diesem Fall w ). Wie alle Ausdrücke wird diese ausgewertet, wenn sie 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 ist in der Funktion selbst enthalten:

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

Beachten Sie, dass NFEs häufig eine Fehlerquelle für JavaScript-Implementierungen waren. IE8 und frühere Versionen behandeln beispielsweise NFEs völlig falsch und erstellen zwei verschiedene Funktionen zu zwei verschiedenen Zeitpunkten. Frühe 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 weit verbreitet, weshalb die Verwendung von NFEs mit Code für das Web im Allgemeinen immer noch problematisch ist.)

Accessor-Funktionsinitialisierer (ES5 +)

Manchmal schleichen sich Funktionen weitgehend unbemerkt ein. das 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 bei der Verwendung der Funktion nicht () ! Das liegt daran, dass es sich um eine Accessor-Funktion für eine Eigenschaft handelt. Wir bekommen und setzen die Eigenschaft wie üblich, aber hinter den Kulissen wird die Funktion aufgerufen.

Sie können auch Accessor-Funktionen mit Object.defineProperty , Object.defineProperties und dem weniger bekannten zweiten Argument von Object.create .

Pfeilfunktionsausdruck (ES2015 +)

ES2015 bringt uns die Pfeilfunktion. Hier ist ein Beispiel:

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

Sehen Sie, dass n => n * 2 in der map() versteckt ist? Das ist eine Funktion.

Ein paar Dinge zu Pfeilfunktionen:

  1. Das haben sie nicht. Stattdessen schließen sie das this des Kontextes, in dem sie definiert sind. (Sie schließen auch arguments und, falls zutreffend, super .) Dies bedeutet, dass das in ihnen dasselbe ist wie das, an dem sie erstellt wurden, und nicht geändert werden kann.

  2. Wie Sie bereits bemerkt haben, verwenden Sie die Keyword- function . Verwenden Sie stattdessen => .

Das obige Beispiel n => n * 2 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

(Denken Sie daran, dass Array#map den Eintrag als erstes Argument und den Index als zweites übergibt.)

In beiden Fällen ist der Körper der Funktion nur ein Ausdruck. Der Rückgabewert der Funktion ist automatisch das Ergebnis dieses Ausdrucks (Sie verwenden keine explizite return ).

Wenn Sie mehr als nur einen einzelnen Ausdruck ausführen, verwenden Sie {} und eine explizite return (wenn Sie einen Wert zurückgeben müssen) wie üblich:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

Die Version ohne { ... } wird als Pfeilfunktion mit einem Ausdruckskörper oder einem kurzen Körper bezeichnet . (Außerdem: Eine kurze Pfeilfunktion.) Die mit { ... } definierte Körperform ist eine Pfeilfunktion mit einem Funktionskörper . (Auch: Eine verbose Pfeilfunktion.)

Methodendeklaration im Objektinitialisierer (ES2015 +)

ES2015 ermöglicht eine kürzere Form der Deklaration einer Eigenschaft, die auf eine Funktion verweist. es sieht aus wie das:

var o = {
    foo() {
    }
};

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

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

Konstruktor- und Methodendeklarationen in der class (ES2015 +)

ES2015 enthält class , einschließlich deklarierter Konstruktoren und Methoden:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Es gibt zwei Funktionsdeklarationen: Eine für den Konstruktor, der den Namen Person erhält, und eine für getFullName , eine Funktion, die Person.prototype zugewiesen Person.prototype .


Wenn Sie über den globalen Kontext sprechen, erzeugen sowohl die var Anweisung als auch eine FunctionDeclaration am Ende eine nicht löschbare Eigenschaft für das globale Objekt. Der Wert von beiden kann jedoch überschrieben werden .

Der kleine Unterschied zwischen den beiden Möglichkeiten besteht darin, dass bei Ausführung des Variablen-Instantiierungsprozesses (vor der eigentlichen Codeausführung) alle mit var deklarierten Bezeichner mit undefined initialisiert werden und die von den FunctionDeclaration verwendeten seit diesem Moment verfügbar sind Beispiel:

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

Die Zuweisung des FunctionExpression erfolgt bis zur Laufzeit.

Eine globale Eigenschaft, die von einer FunctionDeclaration kann wie ein Variablenwert problemlos überschrieben werden, z.

 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 Prüfen eines Aufrufstapels) sehr nützlich sein kann.

Zu Ihrem bearbeiteten ersten Beispiel ( foo = function() { alert('hello!'); }; ) Handelt es sich um eine nicht deklarierte Zuweisung. Ich würde Sie dringend dazu ermutigen, immer das Schlüsselwort var .

Wenn bei einer Zuweisung ohne die var Anweisung der referenzierte Bezeichner nicht in der Gültigkeitsbereichskette gefunden wird, wird er zu einer löschbaren Eigenschaft des globalen Objekts.

Nicht deklarierte Zuweisungen werfen auch einen ReferenceError auf ECMAScript 5 im strengen Modus .

Muss man lesen:

Hinweis : Diese Antwort wurde aus einer anderen Frage zusammengeführt , in der der Hauptzweifel und Missverständnis des OP darin bestand, dass mit einer FunctionDeclaration deklarierte Kennungen nicht überschrieben werden konnten, was nicht der Fall ist.


Gregs Answer ist gut genug, aber ich möchte noch etwas hinzufügen, was ich gerade bei Douglas Crockfords Videos gelernt habe .

Funktionsausdruck:

var foo = function foo() {};

Funktionsaussage:

function foo() {};

Die Funktionsanweisung ist nur eine Abkürzung für varAnweisung mit einem functionWert.

So

function foo() {};

erweitert zu

var foo = function foo() {};

Welche weiter ausdehnt auf:

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

Und beide werden an den Anfang des Codes angehoben.


Hoisting handelt es sich um eine Aktion des JavaScript-Interpreters, bei der alle Variablen- und Funktionsdeklarationen an den Anfang des aktuellen Gültigkeitsbereichs verschoben werden.

Es werden jedoch nur die eigentlichen Deklarationen gehisst. indem Sie die Aufträge dort lassen, wo sie sind.

  • Variablen / Funktionen, die innerhalb der Seite deklariert werden, sind global und können überall auf diese Seite zugreifen.
  • Die innerhalb der Funktion deklarierten Funktionen der Variablen haben lokalen Gültigkeitsbereich. bedeutet, dass sie innerhalb des Funktionskörpers (Gültigkeitsbereichs) verfügbar sind / abgerufen werden können, außerhalb des Funktionskörpers.

Variable

Javascript wird als lose eingegebene Sprache bezeichnet. Was bedeutet, dass Javascript-Variablen einen beliebigen Data-Type . Javascript sorgt automatisch dafür, dass der Variablentyp basierend auf dem zur Laufzeit bereitgestellten 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';
}
  • Funktionen, die innerhalb der Seite deklariert sind, werden an den Anfang der Seite mit globalem Zugriff gehoben.
  • Funktionen, die innerhalb des Funktionsblocks deklariert wurden, werden an den Anfang des Blocks angehoben.
  • Standardrückgabewert der Funktion ist ' undefined ', Standardwert der Variablendeklaration 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 zugewiesen 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 als interpretiert

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 mit jsperf Test Runner

Funktionsklassen des ES5-Konstruktors : Funktionsobjekte, die mit Function.prototype.bind erstellt wurden

JavaScript behandelt Funktionen als erstklassige Objekte. Da Sie also ein Objekt sind, können Sie einer Funktion 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

ES6 eingeführt Pfeil Funktion : Ein Pfeil Funktionsausdruck hat eine kürzere Syntax, sie am besten geeignet sind für Nicht-Methode funktioniert, und sie können nicht als Konstrukteuren verwendet werden.

ArrowFunction : ArrowParameters => ConciseBody .

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd

Der Unterschied besteht darin, dass functionOne ein Funktionsausdruck ist und daher nur definiert wird, wenn diese Zeile erreicht ist, während functionTwo eine Funktionsdeklaration ist und definiert wird, sobald die umgebende Funktion oder das Skript ausgeführt wird (aufgrund des hoisting ).

Zum Beispiel einen 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!");
}

Das bedeutet auch, dass Sie Funktionen nicht mit Funktionsdeklarationen bedingt definieren können:

if (test) {
   // Error or misbehavior
   function functionThree() { doSomething(); }
}

Das obige definiert eigentlich functionThree unabhängig vom test - es sei denn, die use strict ist in Kraft. In diesem Fall wird einfach ein Fehler ausgegeben.


gibt ein Beispiel, in dem er eine zugewiesene Funktion benennt, um sieshortcut() als interne Referenz auf sich selbst verwenden zu können. John Resig gibt ein anderes Beispiel - das Kopieren einer rekursiven Funktion, die einem anderen Objekt in seinem Lernprogramm für fortgeschrittenes Javascript zugewiesen ist . Während das Zuweisen von Funktionen zu Eigenschaften nicht unbedingt die Frage ist, empfehle ich, 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 Belieben 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 nennen, die rekursiv aufgerufen wird, werden die Tests bestanden. (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." );

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 der normale Weg, eine Funktion in JavaScript zu erstellen (anonyme Funktionsdeklaration) :

1. Funktionsausdruck

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

Ein Funktionsausdruck definiert eine Funktion als Teil einer größeren Ausdruckssyntax (normalerweise eine Variablenzuweisung). Mit 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).

Wenn Sie einer Funktion eine Variable zuweisen, bedeutet dies kein Hoisting, da wir wissen, dass Funktionen in JavaScript Hoist sind, können sie aufgerufen werden, bevor sie deklariert werden, während Variablen deklariert werden müssen, bevor Sie auf sie zugreifen können. In diesem Fall bedeutet dies nicht Greifen Sie auf die Funktion zu, wo sie deklariert wurde. Es könnte auch eine Möglichkeit sein, wie Sie Ihre Funktionen schreiben. Für die Funktionen, die eine andere Funktion zurückgeben, könnte diese Art der Deklaration sinnvoll sein. Auch in ECMA6 und oben können Sie diese Funktion einer Pfeilfunktion zuordnen kann verwendet werden, um anonyme Funktionen aufzurufen. Auch diese Deklarationsmethode ist eine bessere Methode, Constructor-Funktionen 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 Funktionsblöcken verschachtelt werden. Es ist hilfreich, sie als Geschwister von Variablendeklarationen 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, noch bevor Sie sie deklarieren, da in JavaScript alle Funktionen Hoisted werden. Wenn Sie jedoch 'use strict' verwenden, wird dies nicht wie erwartet Hoist sein alle normalen Funktionen aufzurufen, die keine großen Zeilen haben und keine Konstruktorfunktion sind.

Wenn Sie weitere Informationen zur Funktionsweise von Hebezeugen in JavaScript benötigen, besuchen Sie den folgenden Link:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting


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.

Möglicherweise möchten Sie wissen, was eine Funktionsdeklaration und ein Funktionsausdruck ist.

Eine Funktionsdeklaration definiert eine benannte Funktionsvariable, ohne dass eine Variablenzuweisung erforderlich ist. Funktionsdeklarationen treten als eigenständige Konstrukte auf und können nicht in Nicht-Funktionsblöcken verschachtelt werden.

function foo() {
    return 3;
}

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

In obiger Bedingung ist der Funktionsname innerhalb seines Gültigkeitsbereichs und des Gültigkeitsbereichs des übergeordneten Elements sichtbar (sonst wäre er nicht erreichbar).

Und in einem Funktionsausdruck

Ein Funktionsausdruck definiert eine Funktion als Teil einer größeren Ausdruckssyntax (normalerweise eine Variablenzuweisung). Funktionen, die über Funktionsausdrücke definiert werden, 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
Funktionsbezeichner opt (FormalParameterList opt ) {FunctionBody}


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) ist 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 diesen link


Eine Funktionsdeklaration und ein Funktionsausdruck, der einer Variablen zugewiesen ist, verhalten sich nach dem Herstellen der Bindung gleich.

Es gibt jedoch einen Unterschied, wie und wann das Funktionsobjekt seiner Variablen tatsächlich zugeordnet ist. Dieser Unterschied ist auf den Mechanismus zurückzuführen, der in JavaScript als Variable Hissen bezeichnet wird .

Grundsätzlich werden alle Funktionsdeklarationen und Variablendeklarationen an die Spitze der Funktion angehoben, in der die Deklaration auftritt (deshalb sagen wir, dass JavaScript Funktionsumfang hat ).

  • 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 gehisst wird, folgt die Initialisierung nicht , sondern wird "zurückgelassen". Die Variable wird initialisiert , um undefinedzu Beginn des Funktionskörpers, und wird in zugeordneten Wert an seiner ursprünglichen Stelle im Code. (Tatsächlich wird ihm an jeder Stelle ein Wert zugewiesen, an dem eine Deklaration einer Variablen mit demselben Namen auftritt.)

Die Reihenfolge beim Heben ist ebenfalls wichtig: Funktionsdeklarationen haben Vorrang vor Variablendeklarationen mit demselben Namen und die letzte Funktionsdeklaration hat Vorrang vor vorherigen 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 barspielt 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 "klebt".

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

In diesem Beispiel awird das aus der Auswertung der zweiten Funktionsdeklaration resultierende Funktionsobjekt initialisiert 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 Zuweisung wird der äußeren Variablen nicht zugewiesen a.


Es gibt drei bemerkenswerte Vergleiche zwischen den zwei verschiedenen Funktionsdeklarationen, die unten aufgeführt sind.

  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;
}

Folgendes funktioniert nicht (weil das das var add=übertrifft function add()).

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

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

Folgendes funktioniert nicht, da addes nach seiner Verwendung deklariert wird.

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

var add=function(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 eine Funktion als deklariert ist function(){}, ist ansonsten die Funktion .name die erste Variable, in der die Funktion gespeichert 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 der leere String ( "").

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

Während die Variable, der die Funktion ursprünglich zugewiesen wird, den Namen festlegt, ändern aufeinanderfolgende, auf die Funktion gesetzte Variablen 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 Firefox's Spidermonkey kann es einige Mikrosekunden-JIST-Kompilierungsunterschiede geben, aber letztendlich ist das Ergebnis das gleiche. Um dies zu beweisen, untersuchen wir die Effizienz von JSPerf bei Mikrobenchmarks durch Vergleichen der Geschwindigkeit zweier leerer Codeausschnitte. Die JSPerf-Tests finden Sie hier . Und die Tests von jsben.ch finden Sie hier . Wie Sie sehen, gibt es einen merklichen Unterschied, wenn es keinen geben sollte. Wenn Sie wirklich ein Performance-Freak wie ich sind, lohnt es sich vielleicht mehr, zu versuchen, die Anzahl der Variablen und Funktionen im Gültigkeitsbereich zu reduzieren und insbesondere den Polymorphismus zu eliminieren (beispielsweise die Verwendung derselben Variablen zum Speichern zweier verschiedener Typen).

Was ist der "nächstgelegene Block"

Der "nächste Block" ist die nächstgelegene "Funktion" (einschließlich asynchroner Funktionen, Generatorfunktionen und asynchroner Generatorfunktionen). Interessanterweise function functionName() {}verhält sich a jedoch wie ein var functionName = function() {}in einem Nicht-Verschlussblock befindlicher Gegenstand 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;
    }
})();


Ich liste die Unterschiede unten auf:

  1. Eine Funktionsdeklaration kann an beliebiger Stelle im Code platziert werden. Auch wenn es aufgerufen wird, bevor die Definition im Code erscheint, wird sie ausgeführt, wenn die Funktionsdeklaration in den Speicher geschrieben oder auf eine Weise angehoben wird, bevor ein anderer Code auf der Seite die Ausführung startet.

    Schauen Sie sich die Funktion unten 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
    

    Wenn ein Funktionsausdruck vor dem Aufruf nicht definiert wurde, führt dies zu einem Fehler. Auch hier wird die Funktionsdefinition selbst nicht nach oben verschoben oder wie in den Funktionsdeklarationen in den Speicher geschrieben. Die Variable, der wir die Funktion zuweisen, wird jedoch angehoben, undefined 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 so 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 Nichtfunktionsblöcken zu schreiben, z. B. wenn auf sie nicht zugegriffen werden kann.

    if (test) {
        function x() { doSomething(); }
    }
    
  3. Benannte Funktionsausdrücke wie der unten stehende funktionieren möglicherweise nicht in Internet Explorer-Browsern vor Version 9.

    var today = function today() {return new Date()}
    

Ich verwende den variablen Ansatz in meinem Code aus einem ganz bestimmten Grund, dessen Theorie oben abstrakt beschrieben wurde, aber ein Beispiel könnte einigen Leuten wie mir mit begrenztem JavaScript-Know-how helfen.

Ich habe Code, den ich mit 160 unabhängig entwickelten Brandings ausführen muss. Der größte Teil des Codes befindet sich in gemeinsam genutzten Dateien, Branding-spezifische Inhalte befinden sich jedoch in einer separaten Datei, und zwar für jedes Branding.

Einige Brandings erfordern bestimmte Funktionen, andere nicht. Manchmal muss ich neue Funktionen hinzufügen, um brandneue spezifische Dinge zu tun. Ich bin froh, den gemeinsam genutzten Code zu ändern, aber ich möchte nicht alle 160 Branding-Dateien ändern.

Mit 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, für die eine bestimmte Implementierung der Funktion erforderlich ist, können ihre Version der Funktion definieren und diese der Variablen zuweisen, wenn sie möchten, und der Rest tut nichts. Ich kann auf eine Nullfunktion testen, bevor ich sie im gemeinsam genutzten Code ausführen kann.

Aus den obigen Kommentaren der Leute ist ersichtlich, dass es auch möglich ist, eine statische Funktion neu zu definieren, aber ich denke, die variable Lösung ist schön und klar.





idioms