Was ist der Unterschied zwischen dem Importieren eines Funktionsausdrucks oder einer Funktionsdeklaration von einem ES6-Modul?

8

Wie ich es verstehe ( siehe Abschnitt 16.3.2.1 ), erlaubt ES6 verschiedene Syntaxen für Funktions- / Klassenexportoperanden. Der Unterschied bezieht sich darauf, ob die exportierte Funktion beim Import als Funktionsdeklaration interpretiert werden soll. In diesem Fall schreiben Sie: export default function () {} // (a) oder als Funktionsausdruck: export default (function () {}); // (b) .

Als mögliche Nebenbemerkung: Ich habe gelesen, dass Importe hochgezogen werden, aber ich bin mir nicht sicher, was das in diesem Zusammenhang bedeutet.

Nehmen wir den Fall dieses Beispiels:

import foo from 'my_module'; // (c)

Wie ich es verstehe, speichert die obige Anweisung meine exportierte Funktion in einer foo -Variable. Ist diese Variable gehisst, oder was ist und wann?

Am wichtigsten ist, was ist der Unterschied (hinsichtlich der Einstellung foo ), wenn my_module die Funktion mit (a) exportiert und wenn sie mit (b) exportiert?

    
c10b10 05.02.2016, 11:32
quelle

1 Antwort

14

Ihre Frage ist ein wenig verworren, aber ich werde mein Bestes versuchen, alles zu erklären.

Stellen wir zuerst fest, wie Module im Allgemeinen funktionieren. Ein Modul hat eine Reihe von exportierten Namen, von denen jeder auf eine lokale Variable in diesem Modul verweist. Der Name des Exports muss nicht mit dem Namen der lokalen Bindung übereinstimmen. Einer der exportierten Namen kann default sein, für den es eine spezielle Syntax gibt (sowohl beim Exportieren als auch beim Importieren), die für den Fall vorgesehen ist, dass ein Modul nur eine einzige Sache exportiert.

  

Ich habe gelesen, dass Importe hochgezogen werden, aber ich bin mir nicht sicher, was das in diesem Zusammenhang bedeutet:

%Vor%

Ja, Import-Deklarationen werden gehisst. Ähnlich wie ein var oder function (und eigentlich wie jede andere Deklaration ) ist der Bezeichner foo richtig verfügbar von Anfang an, bevor irgendwelche Anweisungen im Modul ausgeführt werden. Tatsächlich wird die Bindung sogar vor denen von deklarierten var iables erstellt.

Der Unterschied besteht darin, wie sie initialisiert werden:

  • var s werden mit undefined initialisiert
  • function s und function* s werden mit dem Funktionsobjekt
  • initialisiert
  • let , const und class es sind nicht initialisiert
  • importierte Bindungen sind nicht einmal wirklich initialisiert, sie werden als Zeiger auf die lokale Variable erstellt, auf die der exportierte Name im importierten Modul
  • verweist
  • importierte Module ( import * as … ) werden mit einem Modulobjekt (dessen Eigenschaften auch solche Zeiger sind) initialisiert
  

Wann ist foo auf meine exportierte Funktion eingestellt?

Die kurze Antwort: vor allem anderen.

Die lange Antwort: Es ist nicht wirklich festgelegt. Es ist ein Verweis auf die lokale Variable im importierten Modul, von der Sie erwarten, dass sie die Funktion enthält. Die lokale Variable kann sich ändern, wenn sie nicht const ist - aber das erwarten wir normalerweise nicht. Normalerweise enthält es diese Funktion bereits, weil das importierte Modul vollständig ausgewertet wird, bevor die Module, die es importieren, sind. Also, wenn Sie befürchten, dass es ein Problem mit var Funktionsname = Funktion () {} vs Funktion Funktionsname () {} gibt, können Sie sein erleichtert - da ist es nicht.

Nun zurück zu Ihrer Titelfrage:

  

Was ist der Unterschied zwischen dem Export eines Funktionsausdrucks und einer Funktionsdeklaration in einem ES6-Modul?

Nichts Besonderes, die beiden Aspekte haben eigentlich nicht viel miteinander zu tun:

  • export -Deklarationen verknüpfen einen Exportnamen mit einer lokalen Variablen im Modulbereich
  • Alle Variablen im Modulbereich werden wie üblich gehisst
  • Funktionsdeklarationen werden anders als Variablendeklarationen mit einer Zuweisung eines Funktionsausdrucks wie üblich initialisiert

Natürlich gibt es immer noch keine guten Gründe, die mehr deklarativen Funktionsdeklarationen nicht überall zu verwenden; Dies ist bei ES6-Modulen nicht anders als zuvor. Wenn überhaupt, könnte es sogar weniger Gründe für die Verwendung von Funktionsausdrücken geben, da alles durch Deklarationen abgedeckt ist:

%Vor%

%Vor%

Ok, die letzten beiden Standard-Export-Deklarationen sind eigentlich ein bisschen anders als die ersten beiden. Die lokale ID, die mit dem exportierten Namen default verknüpft ist, ist nicht foo , sondern *default* - sie kann nicht neu zugewiesen werden. Dies ist im letzten Fall sinnvoll (wo es keinen Namen foo gibt), aber im vorletzten Fall sollten Sie feststellen, dass foo wirklich nur ein lokaler Alias ​​ist, nicht die exportierte Variable selbst. Ich würde empfehlen, dieses Muster zu verwenden.

Oh, und bevor Sie fragen: Ja, dieser letzte Standard-Export ist wirklich auch eine Funktionsdeklaration, kein Ausdruck. Eine anonyme Funktionsdeklaration . Das ist neu bei ES6: -)

  

Was genau ist der Unterschied zwischen export default function () {} und export default (function () {});

?

Sie sind für jeden Zweck ziemlich gleich. Sie sind anonyme Funktionen mit einer .name -Eigenschaft "default" , die von der speziellen *default* -Bindung gehalten werden, auf die der exportierte Name default für anonyme Exportwerte zeigt.
Ihr einziger Unterschied ist das Hochziehen - die Deklaration wird ihre Funktion am Anfang des Moduls instanziiert bekommen, der Ausdruck wird nur ausgewertet, sobald die Ausführung des Modulcodes die Anweisung erreicht. Da es für sie jedoch keine Variable mit einem zugänglichen Namen gibt, ist dieses Verhalten außer einem sehr merkwürdigen Spezialfall nicht beobachtbar: ein Modul, das sich selbst importiert. Ähm, ja.

%Vor%

%Vor%

Du solltest wirklich keines dieser Dinge tun. Wenn Sie eine exportierte Funktion in Ihrem Modul verwenden möchten, geben Sie ihr in der Deklaration einen Namen.

  

Warum haben in diesem Fall beide Syntaxen?

passiert.Es ist erlaubt durch die Spezifikation, da es keine zusätzlichen Ausnahmen gibt, um bestimmte unsinnige Dinge zu verbieten. Es ist nicht beabsichtigt zu verwenden. In diesem Fall werden die function - und class -Ausdrücke in export default -Anweisungen sogar explizit deaktiviert und stattdessen als Deklarationen behandelt. Mit dem Gruppierungsoperator haben Sie eine Lücke gefunden. Gut gemacht. Missbrauche es nicht.

    
Bergi 05.02.2016, 13:54
quelle