Ein Artikel, der die Modularität in es6 im Detail erklärt
CommonJs
hat viele hervorragende Funktionen. Schauen wir uns diese im Folgenden kurz an: CommonJs
有很多优秀的特性,下面我们再简单的回顾一下:
模块代码只在加载后运行;
模块只能加载一次;
模块可以请求加载其他模块;
支持循环依赖;
模块可以定义公共接口,其他模块可以基于这个公共接口观察和交互;
天下苦 CommonJs 久矣
Es Module
的独特之处在于,既可以通过浏览器原生加载,也可以与第三方加载器和构建工具一起加载。
支持 Es module
模块的浏览器可以从顶级模块加载整个依赖图,且是异步完成。浏览器会解析入口模块,确定依赖,并发送对依赖模块的请求。这些文件通过网络返回后,浏览器就会解析它们的依赖,,如果这些二级依赖还没有加载,则会发送更多请求。
这个异步递归加载过程会持续到整个应用程序的依赖图都解析完成。解析完成依赖图,引用程序就可以正式加载模块了。
Es Module
不仅借用了 CommonJs
和 AMD
的很多优秀特性,还增加了一些新行为:
Es Module
默认在严格模式下执行;Es Module
不共享全局命名空;Es Module
顶级的this
的值是undefined
(常规脚本是window
);模块中的
var
声明不会添加到window
对象;Es Module
是异步加载和执行的;
export 和 import
模块功能主要由两个命令构成:
exports
和import
。-
export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
export的基本使用
- 导出的基本形式:
export const nickname = "moment"; export const address = "广州"; export const age = 18;
- 当然了,你也可以写成以下的形式:
const nickname = "moment"; const address = "广州"; const age = 18; export { nickname, address, age };
- 对外导出一个对象和函数
export function foo(x, y) { return x + y; } export const obj = { nickname: "moment", address: "广州", age: 18, }; // 也可以写成这样的方式 function foo(x, y) { return x + y; } const obj = { nickname: "moment", address: "广州", age: 18, }; export { foo, obj };
- 通常情况下,
export
输出的变量就是本来的名字,但是可以使用as
关键字重命名。
const address = "广州"; const age = 18; export { nickname as name, address as where, age as old };
- 默认导出,值得注意的是,一个模块只能有一个默认导出:
export default "foo"; export default { name: 'moment' } export default function foo(x,y) { return x+y } export { bar, foo as default };
export 的错误使用
- 导出语句必须在模块顶级,不能嵌套在某个块中:
if(true){ export {...}; }
export
必须提供对外的接口:
// 1只是一个值,不是一个接口 export 1 // moment只是一个值为1的变量 const moment = 1 export moment // function和class的输出,也必须遵守这样的写法 function foo(x, y) { return x+y } export foo
import的基本使用
- 使用
export
命令定义了模块的对外接口以后,其他js文件就可以通过import
命令加载整个模块
import {foo,age,nickname} form '模块标识符'
- 模块标识符可以是当前模块的相对路径,也可以是绝对路径,也可以是纯字符串,但不能是动态计算的结果,例如凭借的字符串。
import
命令后面接受一个花括弧,里面指定要从其他模块导入的变量名,而且变量名必须与被导入模块的对外接口的名称相同。- 对于导入的变量不能对其重新赋值,因为它是一个只读接口,如果是一个对象,可以对这个对象的属性重新赋值。导出的模块可以修改值,导入的变量也会跟着改变。
- 从上图可以看得出来,对象的属性被重新赋值了,而变量的则报了
Assignment to constant variable
的类型错误。 - 如果模块同时导出了命名导出和默认导出,则可以在
import
语句中同时取得它们。可以依次列出特定的标识符来取得,也可以使用*
来取得:
// foo.js export default function foo(x, y) { return x + y; } export const bar = 777; export const baz = "moment"; // main.js import { default as foo, bar, baz } from "./foo.js"; import foo, { bar, baz } from "./foo.js"; import foo, * as FOO from "./foo.js";
动态 import
- 标准用法的
import
导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。 - 关键字
import
可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个promise
- Der Modulcode ist nur in Run nach dem Laden;
- Module können nur einmal geladen werden;Module können das Laden anderer Module anfordern;🎜
- 🎜Unterstützt zirkuläre Abhängigkeiten;🎜🎜
- 🎜Module können öffentlich definieren Schnittstellen können andere Module basierend auf dieser öffentlichen Schnittstelle beobachten und interagieren nativ über den Browser oder mit Ladeprogrammen und Build-Tools von Drittanbietern geladen werden. 🎜🎜Browser, die das Modul
Es module
unterstützen, können das gesamte Abhängigkeitsdiagramm asynchron vom Modul der obersten Ebene laden. Der Browser analysiert das Eingabemodul, ermittelt die Abhängigkeiten und sendet eine Anfrage für das abhängige Modul. Nachdem diese Dateien über das Netzwerk zurückgegeben wurden, löst der Browser ihre Abhängigkeiten auf. Wenn diese sekundären Abhängigkeiten nicht geladen wurden, werden weitere Anfragen gesendet. 🎜🎜Dieser asynchrone rekursive Ladevorgang wird fortgesetzt, bis das Abhängigkeitsdiagramm der gesamten Anwendung aufgelöst ist. Nachdem das Abhängigkeitsdiagramm analysiert wurde, kann das Referenzprogramm das Modul offiziell laden. 🎜🎜Es Module
übernimmt nicht nur viele hervorragende Funktionen vonCommonJs
undAMD
, sondern fügt auch einige neue Verhaltensweisen hinzu: 🎜- 🎜
Es Module
wird standardmäßig im strikten Modus ausgeführt; 🎜🎜 - 🎜
Es Module
teilt das Globale nicht namespace; 🎜🎜 - 🎜
Es Module
Der Wert vonthis
auf oberster Ebene istundefiniert
(normales Skript istwindow</ code>); 🎜🎜<li>🎜Die <code>var
-Deklaration im Modul wird nicht zumwindow
-Objekt hinzugefügt 🎜🎜 - 🎜
Es Modul
wird asynchron geladen und ausgeführt;🎜🎜🎜🎜export und import🎜
- 🎜Die Modulfunktion besteht hauptsächlich aus zwei Befehlen:
exports< /code> und <code >import
. 🎜🎜 - Der Befehl
export
wird verwendet, um die externe Schnittstelle des Moduls anzugeben, und der Befehlimport
wird verwendet, um die von anderen Modulen bereitgestellten Funktionen zu importieren. 🎜🎜🎜🎜🎜Grundlegende Verwendung von Export🎜🎜🎜- Grundform des Exports: 🎜🎜
import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment });
Nach dem Login kopieren- Natürlich kann man es auch in folgender Form schreiben: 🎜🎜
const p = new Promise((resolve, reject) => { resolve(111); }); // SyntaxError: await is only valid in async functions and the top level bodies of modules const result = await p; console.log(result);
Nach dem Login kopierenNach dem Login kopieren- < li>Exportieren Sie ein Objekt und eine Funktion nach außen 🎜🎜
- Normalerweise ist die von
export
ausgegebene Variable ihr ursprünglicher Name, Sie können jedochas< verwenden /code> Schlüsselwort Umbenennen. 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// 错误 import { &#39;b&#39; + &#39;ar&#39; } from &#39;./foo.js&#39;; // 错误 let module = &#39;./foo.js&#39;; import { bar } from module; // 错误 if (x === 1) { import { bar } from &#39;./foo.js&#39;; } else { import { foo } from &#39;./foo.js&#39;; }</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div><ul><li>Standardexport, es ist zu beachten, dass ein Modul nur einen Standardexport haben kann: 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'><script type="module" src="./main.mjs"></script> <script type="module"></script></pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜🎜🎜export falsche Verwendung🎜🎜🎜<ul><li>Die Exportanweisung muss in sein Das Modul oberste Ebene, kann nicht in einem Block verschachtelt werden: 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'> <script type="module"> console.log("模块情况下的"); </script> <script src="./main.js" type="module" defer></script> <script> console.log("正常 script标签"); </script></pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div><ul><li><code>export
Muss eine externe Schnittstelle bereitstellen: 🎜🎜🎜🎜🎜Grundlegende Verwendung von Import🎜🎜🎜<script src="./foo.js"></script> <script src="./foo.js"></script> <script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script>
Nach dem Login kopierenNach dem Login kopieren- Nachdem der Befehl
export
zum Definieren der externen Schnittstelle des Moduls verwendet wurde, können andere js-Dateien das gesamte Modul über den Befehlimport
laden🎜🎜// main.js import { bar } from "./bar.js"; export const main = "main"; console.log("main"); // foo.js import { main } from "./main.js"; export const foo = "foo"; console.log("foo"); // bar.js import { foo } from "./foo.js"; export const bar = "bar"; console.log("bar");
Nach dem Login kopierenNach dem Login kopieren- Modulidentifikation Das Zeichen kann ein relativer Pfad zum aktuellen Modul, ein absoluter Pfad oder eine reine Zeichenfolge sein, es kann jedoch nicht das Ergebnis einer dynamischen Berechnung sein, z. B. eine Abhängigkeitsfolge. 🎜
import
Der Befehl akzeptiert eine geschweifte Klammer, die den Variablennamen angibt, der aus anderen Modulen importiert werden soll, und der Variablenname muss mit dem Namen der externen Schnittstelle des importierten Moduls identisch sein . 🎜- Die importierte Variable kann nicht neu zugewiesen werden, da es sich um eine schreibgeschützte Schnittstelle handelt. Wenn es sich um ein Objekt handelt, können die Eigenschaften des Objekts neu zugewiesen werden. Exportierte Module können Werte ändern, und importierte Variablen ändern sich ebenfalls entsprechend. 🎜🎜🎜
🎜
- Wie aus dem obigen Bild ersichtlich ist, wurden die Eigenschaften des Objekts neu zugewiesen, während die Variable einen Typfehler von
Zuweisung an konstante Variable</code gemeldet hat >. 🎜<li>Wenn das Modul sowohl benannte Exporte als auch Standardexporte exportiert, können diese gleichzeitig in der <code>import
-Anweisung abgerufen werden. Sie können bestimmte Kennungen auflisten, um sie zu erhalten, oder Sie können*
verwenden, um sie zu erhalten: 🎜🎜rrreee🎜🎜🎜dynamischer Import🎜🎜🎜- Standardverwendung von
import< /code> Die importierten Module sind statisch, was dazu führt, dass alle importierten Module beim Laden kompiliert werden (eine Kompilierung nach Bedarf kann nicht erreicht werden, was die Ladegeschwindigkeit der Homepage verringert). In einigen Szenarien möchten Sie möglicherweise Module basierend auf Bedingungen oder nach Bedarf importieren. In diesem Fall können Sie den dynamischen Import anstelle des statischen Imports verwenden. 🎜<li>Das Schlüsselwort <code>import
kann Module wie den Aufruf einer Funktion dynamisch importieren. Auf diese Weise aufgerufen, wird einpromise
zurückgegeben. 🎜🎜rrreee🎜🎜🎜Verwenden Sie das Warten auf oberster Ebene🎜🎜🎜- 在经典脚本中使用
await
必须在带有async
的异步函数中使用,否则会报错:
const p = new Promise((resolve, reject) => { resolve(111); }); // SyntaxError: await is only valid in async functions and the top level bodies of modules const result = await p; console.log(result);
Nach dem Login kopierenNach dem Login kopieren- 而在模块中,你可以直接使用
Top-level await
:
const p = new Promise((resolve, reject) => { resolve(777); }); const result = await p; console.log(result); // 777正常输出
Nach dem Login kopierenNach dem Login kopierenimport 的错误使用
- 由于
import
是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
// 错误 import { 'b' + 'ar' } from './foo.js'; // 错误 let module = './foo.js'; import { bar } from module; // 错误 if (x === 1) { import { bar } from './foo.js'; } else { import { foo } from './foo.js'; }
Nach dem Login kopierenNach dem Login kopieren在浏览器中使用 Es Module
在浏览器上,你可以通过将
type
属性设置为module
用来告知浏览器将script
标签视为模块。
<script type="module" src="./main.mjs"></script> <script type="module"></script>
Nach dem Login kopierenNach dem Login kopieren- 模块默认情况下是延迟的,因此你还可以使用
defer
的方式延迟你的nomodule
脚本:
<script type="module"> console.log("模块情况下的"); </script> <script src="./main.js" type="module" defer></script> <script> console.log("正常 script标签"); </script>
Nach dem Login kopierenNach dem Login kopieren- 在浏览器中,引入相同的
nomodule
脚本会被执行多次,而模块只会被执行一次:
<script src="./foo.js"></script> <script src="./foo.js"></script> <script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script> <script type="module" src="./main.js"></script>
Nach dem Login kopierenNach dem Login kopieren模块的默认延迟
默认情况下,
nomodule
脚本会阻塞HTML
解析。你可以通过添加defer
属性来解决此问题,该属性是等到HTML
解析完成之后才执行。
defer
和async
是一个可选属性,他们只可以选择其中一个,在nomodule
脚本下,defer
等到HTML
解析完才会解析当前脚本,而async
会和HTML
并行解析,不会阻塞HTML
的解析,模块脚本可以指定async
属性,但对于defer
无效,因为模块默认就是延迟的。- 对于模块脚本,如果存在
async
属性,模块脚本及其所有依赖项将于解析并行获取,并且模块脚本将在它可用时进行立即执行。
Es Module 和 Commonjs 的区别
讨论
Es Module
模块之前,必须先了解Es Module
与Commonjs
完全不同,它们有三个完全不同:CommonJS
模块输出的是一个值的拷贝,Es Module
输出的是值的引用;CommonJS
模块是运行时加载,Es Module
是编译时输出接口。CommonJS
模块的require()
是同步加载模块,ES6 模块的import
命令是异步加载,有一个独立的模块依赖的解析阶段。
第二个差异是因为
CommonJS
加载的是一个对象(即module.exports
属性),该对象只有在脚本运行完才会生成。而Es Module
不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。Commonjs
输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。具体可以看上一篇写的文章。Es Module
的运行机制与CommonJS
不一样。JS引擎
对脚本静态分析的时候,遇到模块加载命令import
,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,import
就是一个连接管道,原始值变了,import
加载的值也会跟着变。因此,Es Module
是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。Es Module 工作原理的相关概念
在学习工作原理之前,我们不妨来认识一下相关的概念。
Module Record
模块记录(
Module Record
) 封装了关于单个模块(当前模块)的导入和导出的结构信息。此信息用于链接连接模块集的导入和导出。一个模块记录包括四个字段,它们只在执行模块时使用。其中这四个字段分别是:Realm
: 创建当前模块的作用域;Environment
:模块的顶层绑定的环境记录,该字段在模块被链接时设置;Namespace
: Das Modul-Namespace-Objekt ist ein Modul-Namespace-Fremdobjekt, das auf Laufzeiteigenschaften basierenden Zugriff auf Modulexportbindungen bietet. Modul-Namespace-Objekte haben keine Konstruktoren;Namespace
:模块命名空间对象是模块命名空间外来对象,它提供对模块导出绑定的基于运行时属性的访问。模块命名空间对象没有构造函数;HostDefined
:字段保留,以按host environments
使用,需要将附加信息与模块关联。
Module Environment Record
- 模块环境记录是一种声明性环境记录,用于表示ECMAScript模块的外部作用域。除了普通的可变和不可变绑定之外,模块环境记录还提供了不可变的
import
绑定,这些绑定提供了对存在于另一个环境记录中的目标绑定的间接访问。
不可变绑定就是当前的模块引入其他的模块,引入的变量不能修改,这就是模块独特的不可变绑定。
Es Module 的解析流程
在开始之前,我们先大概了解一下整个流程大概是怎么样的,先有一个大概的了解:
阶段一:构建(
Construction
),根据地址查找js
文件,通过网络下载,并且解析模块文件为Module Record
;阶段二:实例化(
Instantiation
),对模块进行实例化,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址;阶段三:运行(
Evaluation
),运行代码,计算值,并且将值填充到内存地址中;
Construction 构建阶段
loader
负责对模块进行寻址及下载。首先我们修改一个入口文件,这在HTML
中通常是一个<script type="module"></script>
的标签来表示一个模块文件。
- 模块继续通过
import
语句声明,在import
声明语句中有一个 模块声明标识符(ModuleSpecifier
),这告诉loader
怎么查找下一个模块的地址。
- 每一个模块标识号对应一个
模块记录(Module Record)
,而每一个模块记录
包含了JavaScript代码
、执行上下文
、ImportEntries
、LocalExportEntries
、IndirectExportEntries
、StarExportEntries
。其中ImportEntries
值是一个ImportEntry Records
类型,而LocalExportEntries
、IndirectExportEntries
、StarExportEntries
是一个ExportEntry Records
类型。
ImportEntry Records
- 一个
ImportEntry Records
包含三个字段ModuleRequest
、ImportName
、LocalName
;
ModuleRequest: 一个模块标识符(
ModuleSpecifier
);ImportName: 由
ModuleRequest
模块标识符的模块导出所需绑定的名称。值namespace-object
表示导入请求是针对目标模块的命名空间对象的;LocalName: 用于从导入模块中从当前模块中访问导入值的变量;
- 详情可参考下图:
- 下面这张表记录了使用
import
导入的ImportEntry Records
HostDefined
: Feld für die Verwendung durchHost-Umgebungen
reserviert, für die Zuordnung zum Modul sind zusätzliche Informationen erforderlich.
🎜import React aus "React"; 🎜🎜 "React" 🎜🎜 "Standard" 🎜🎜 "reagieren „🎜🎜🎜🎜import * as Moment from „react“;🎜🎜 „react“🎜🎜namespace-obj🎜🎜 „Moment“🎜🎜🎜🎜import {useEffect} from „react“;🎜🎜 „react“🎜🎜“ useEffect"🎜🎜"useEffect"🎜🎜🎜🎜import {useEffect as effect } from "react";🎜🎜"react"🎜🎜"useEffect"🎜🎜"effect"🎜🎜🎜🎜Module Environment Record Phase 2: Instanziierung (Module Environment Record ist ein deklarativer Umgebungsdatensatz Wird verwendet, um den externen Bereich eines ECMAScript-Moduls darzustellen. Zusätzlich zu den gewöhnlichen veränderlichen und unveränderlichen Bindungen stellen Modulumgebungsdatensätze auch unveränderliche import
-Bindungen bereit, die eine Bindung an ein Ziel ermöglichen, das in einem anderen Umgebungsdatensatz für indirekten Zugriff vorhanden ist.Unveränderliche Bindung bedeutet, dass das aktuelle Modul andere Module einführt und die eingeführten Variablen nicht geändert werden können. Dies ist die einzigartige unveränderliche Bindung des Moduls. Es-Modul-Parsing-Prozess
Bevor wir beginnen, wollen wir uns eine ungefähre Vorstellung davon machen, wie der gesamte Prozess aussieht. Haben Sie ein allgemeines Verständnis: Phase 1: Bau ( Bau
), suchen Sie nach der Adressejs
-Datei, laden Sie sie über das Internet herunter und analysieren Sie die Moduldatei inModule Record
;Instantiation</ code>), instanziieren Sie das Modul, weisen Sie Speicherplatz zu, analysieren Sie die Import- und Exportanweisungen des Moduls und verweisen Sie das Modul auf die entsprechende Speicheradresse;</p><tbody><tr><td>Phase 3: Ausführen (<code>Evaluation</ Code>), Führen Sie den Code aus, berechnen Sie den Wert und geben Sie den Wert in die Speicheradresse ein;</p></td><td></td><strong><span style="font-size: 18px;">Bauphase</span ></strong>< /p><ul><td><code>loader
ist für die Adressierung und den Download von Modulen verantwortlich. Zuerst ändern wir eine Eintragsdatei, die inHTML
normalerweise ein<script type="module"></script>
-Tag ist, um eine Moduldatei darzustellen.p>
- Das Modul wird weiterhin über die
import
-Anweisung deklariert. Es gibt eine Moduldeklarationskennung (ModuleSpecifier
) imimport
Diese Anweisung teilt demloader
mit, wie er die Adresse des nächsten Moduls finden soll. ModuleRequest: eine Modulkennung (p>
Jede Modulidentifikationsnummer entspricht einem Moduldatensatz
, und jederModuldatensatz
enthältJavaScript-Code
undAusführungskontext
,ImportEntries
,LocalExportEntries
,IndirectExportEntries
,StarExportEntries
. Der WertImportEntries
ist vom TypImportEntry Records
undLocalExportEntries
,IndirectExportEntries
,StarExportEntries
Ist einExportEntry Records
-Typ. EinImportEntry Records
ImportEntry Records
enthält drei FelderModuleRequest</ code>, <code>ImportName
,LocalName
;ModuleSpecifier
);ImportName: von ModuleRequest
Der Name der Bindung, die für den Modulexport der Modulkennung erforderlich ist. Der Wertnamespace-object
gibt an, dass die Importanforderung für das Namespace-Objekt des Zielmoduls gilt;LocalName: Variable, die verwendet wird, um vom importierten Modul aus auf den importierten Wert aus dem aktuellen Modul zuzugreifen; Weitere Informationen finden Sie im Bild unten:In der folgenden Tabelle sind Instanzen des Felds ImportEntry Records
aufgeführt, die mitimport
importiert wurden:Import Statement Formular) Module Identifier (ModUleRequest) import Name (Importname) Lokaler Name (Lokalname) ExportEntry Records
- Ein
ExportEntry Records
enthält vier FelderExportName
,ModuleRequest
,ImportName
, < code>LocalName, der sich vonImportEntry Records
unterscheidet, verfügt über einen zusätzlichenExportName
.
ExportName: Der Name, den dieses Modul zum Binden beim Exportieren verwendet.
ExportEntry Records
包含四个字段ExportName
、ModuleRequest
、ImportName
、LocalName
,和ImportEntry Records
不同的是多了一个ExportName
。 - 在经典脚本中使用
ExportName: 此模块用于导出时绑定的名称。
下面这张表记录了使用
export
导出的ExportEntry Records
In der folgenden Tabelle sind Instanzen des Felds
ExportEntry Records
aufgeführt, die mitexport
exportiert wurden: Lokaler NameExportdeklaration Exportname Modulbezeichner Name importieren "v"Var v exportieren; "v" null null Standardfunktion f() {} exportieren „Standard“null null "f" Standardfunktion exportieren () {} "default" null null "default ""default" null null "default "export {x}; "x" null null "x" "x" null null "v" export {x} aus "mod"; "x" "mod" "x" export {v als „ all-but-default null export * as ns from „mod“; “ns “mod“ all null Zurück zum Thema
Erst nach dem Parsen des aktuellen
Moduldatensatzes
können Sie wissen, von welchen Submodulen das aktuelle Modul abhängt, und dann müssen Sie dasauflösen
Submodules-Modul, rufen Sie das Submodul ab, analysieren Sie dann das Submodul und durchlaufen Sie diesen Prozess des Auflösens –> img src="https://img. php.cn/upload/article/000/000/024/1b9e89096e472cf2a4b00b9cb0217af0-7.png" alt="Ein Artikel, der die Modularität in es6 im Detail erklärt" loading="lazy"/>Module Record
之后,才能知道当前模块依赖的是那些子模块,然后你需要resolve
子模块,获取子模块,再解析子模块,不断的循环这个流程 resolving -> fetching -> parsing,结果如下图所示:- 这个过程也称为
静态分析
,不会运行JavaScript代码,只会识别export
和import
关键字,所以说不能在非全局作用域下使用import
,动态导入除外。 - 如果多个文件同时依赖一个文件呢,这会不会引起死循环,答案是不会的。
loader
使用Module Map
对全局的MOdule Record
进行追踪、缓存这样就可以保证模块只被fetch
一次,每个全局作用域中会有一个独立的 Module Map。
MOdule Map 是由一个 URL 记录和一个字符串组成的key/value的映射对象。URL记录是获取模块的请求URL,字符串指示模块的类型(例如。“javascript”)。模块映射的值要么是模块脚本,null(用于表示失败的获取),要么是占位符值“fetching(获取中)”。
linking 链接阶段
- 在所有
Module Record
被解析完后,接下来 JS 引擎需要把所有模块进行链接。JS 引擎以入口文件的Module Record
作为起点,以深度优先的顺序去递归链接模块,为每个Module Record
创建一个Module Environment Record
,用于管理Module Record
中的变量。
Module Environment Record
中有一个Binding
,这个是用来存放Module Record
导出的变量,如上图所示,在该模块main.js
处导出了一个count
的变量,在Module Environment Record
中的Binding
就会有一个count
,在这个时候,就相当于V8
的编译阶段,创建一个模块实例对象,添加相对应的属性和方法,此时值为undefined
或者null
,为其分配内存空间。- 而在子模块
count.js
中使用了import
关键字对main.js
进行导入,而count.js
的import
和main.js
的export
的变量指向的内存位置是一致的,这样就把父子模块之间的关系链接起来了。如下图所示:
- 需要注意的是,我们称
export
导出的为父模块,import
引入的为子模块,父模块可以对变量进行修改,具有读写权限,而子模块只有读权限。
Evaluation 求值阶段
- 在模块彼此链接完之后,执行对应模块文件中顶层作用域的代码,确定链接阶段中定义变量的值,放入内存中。
Es module 是如何解决循环引用的
在
Es Module
中有5种状态,分别为unlinked
、linking
、linked
、evaluating
和evaluated
,用循环模块记录(Cyclic Module Records
)的Status
字段来表示,正是通过这个字段来判断模块是否被执行过,每个模块只执行一次。这也是为什么会使用Module Map
来进行全局缓存Module Record
的原因了,如果一个模块的状态为evaluated
,那么下次执行则会自动跳过,从而包装一个模块只会执行一次。Es Module
采用深度优先
- This Der Prozess wird auch
statische Analyse
genannt, führt keinen JavaScript-Code aus und erkennt nur die Schlüsselwörterexport
undimport
, alsoimport< /code kann nicht in nicht-globalen Bereichen > verwendet werden, außer beim dynamischen Import. 🎜🎜Was passiert, wenn mehrere Dateien gleichzeitig von einer Datei abhängen? Wird dies eine Endlosschleife verursachen? 🎜🎜<code>loader
verwendetModule Map
, um den globalenMOdule Record
zu verfolgen und zwischenzuspeichern, um sicherzustellen, dass Module nurfetch
> sind Einmal gibt es in jedem globalen Bereich eine unabhängige Modulzuordnung. 🎜🎜MOdule Map ist ein Schlüssel/Wert-Zuordnungsobjekt, das aus einem URL-Datensatz und einer Zeichenfolge besteht. Der URL-Datensatz ist die Anforderungs-URL zum Abrufen des Moduls, eine Zeichenfolge, die den Modultyp angibt (z. B. „Javascript“). Der Wert der Modulzuordnung ist entweder das Modulskript, null (wird verwendet, um einen fehlgeschlagenen Abruf anzuzeigen) oder der Platzhalterwert „fetching“. 🎜
🎜🎜🎜Verknüpfungsphase🎜
- 🎜Nachdem alle
Moduldatensätze
analysiert wurden, dann muss die JS-Engine alle Module verknüpfen. Die JS-Engine verwendet denModule Record
der Eintragsdatei als Ausgangspunkt, verknüpft die Module rekursiv in der Reihenfolge der Tiefe zuerst und erstellt einenModule Environment Record</ für jedes <code>Modul Datensatz
, wird zum Verwalten von Variablen imModuldatensatz
verwendet. 🎜🎜
- 🎜
Module Environment Record
hat eineBinding
, die zum Speichern von Variablen verwendet wird, die vonModule Record
exportiert werden, wie in der Abbildung gezeigt Oben wird eine Variable voncount
inmain.js
dieses Moduls undBinding
imModule Environment Record
exportiert Es wird einencount
geben. Dies entspricht der Kompilierungsphase vonV8
, bei der ein Modulinstanzobjekt erstellt und die entsprechenden Attribute und Methoden hinzugefügt werden Dieses Mal istundefiniert
odernull
, reservieren Sie dafür Speicherplatz. 🎜🎜Das Schlüsselwortimport
wird im Untermodulcount.js
verwendet, ummain.js
undcount.js zu importieren Die Speicherorte, auf die die Variablen von <code>import
von undexport
vonmain.js
verweisen, sind identisch und werden somit getrennt Eltern- und Kindermodule sind verknüpft. Wie im Bild unten gezeigt: 🎜🎜
- 🎜Es sollte beachtet werden, dass wir das, was
export
exportiert, als übergeordnetes Modul bezeichnen und wasimport
einführt, als Untermodul. Das übergeordnete Modul kann Variablen mit Lese- und Schreibberechtigungen ändern, während Untermodule nur Leseberechtigungen haben. 🎜- 🎜Nachdem die Module miteinander verknüpft sind, führen Sie die entsprechenden Schritte aus Moduldatei Der Code im Top-Level-Bereich bestimmt den Wert der in der Linkphase definierten Variablen und legt ihn im Speicher ab. 🎜
Wie das Es-Modul Zirkelverweise löst
- 🎜🎜Es gibt 5 Typen im
Es-Modul
-Status, jeweilsunlinked
,linking
,linked
,evaluating
undevaluated
, verwenden Es wird dargestellt anhand des FeldsStatus
der zyklischen Moduldatensätze (Cyclic Module Records
). Anhand dieses Felds wird beurteilt, ob das Modul nur einmal ausgeführt wurde . Aus diesem Grund wirdModule Map
auch zum globalen Zwischenspeichern vonModule Record
verwendet. Wenn der Status eines Modulsevalued
ist, wird dies bei der nächsten Ausführung der Fall sein automatisch übersprungen, so dass das Packen eines Moduls nur einmal durchgeführt wird.Es Modul
verwendet die MethodeTiefe zuerst
, um den Modulgraphen zu durchlaufen. Jedes Modul wird nur einmal ausgeführt, wodurch eine Endlosschleife vermieden wird. 🎜
深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
- 看下面的例子,所有的模块只会运行一次:
// main.js import { bar } from "./bar.js"; export const main = "main"; console.log("main"); // foo.js import { main } from "./main.js"; export const foo = "foo"; console.log("foo"); // bar.js import { foo } from "./foo.js"; export const bar = "bar"; console.log("bar");
Nach dem Login kopierenNach dem Login kopieren- 通过
node
运行main.js
,得出以下结果:
好了,这篇文章到这也就结束了。
原文地址:https://juejin.cn/post/7166046272300777508
【推荐学习:javascript高级教程】
Das obige ist der detaillierte Inhalt vonEin Artikel, der die Modularität in es6 im Detail erklärt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!
Erklärung dieser WebsiteDer Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cnHeiße KI -Werkzeuge
Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos
AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.
Undress AI Tool
Ausziehbilder kostenlos
Clothoff.io
KI-Kleiderentferner
AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.
Heißer Artikel
R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌R.E.P.O. Beste grafische Einstellungen3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌Assassin's Creed Shadows: Seashell Riddle -Lösung2 Wochen vor By DDDR.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌WWE 2K25: Wie man alles in Myrise freischaltet4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌Heiße Werkzeuge
Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor
SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen
Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung
Dreamweaver CS6
Visuelle Webentwicklungstools
SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)
Heiße Themen
CakePHP-Tutorial1376
52
PHP und Vue: eine perfekte Kombination von Front-End-Entwicklungstools Mar 16, 2024 pm 12:09 PM
PHP und Vue: eine perfekte Kombination von Front-End-Entwicklungstools In der heutigen Zeit der rasanten Entwicklung des Internets ist die Front-End-Entwicklung immer wichtiger geworden. Da Benutzer immer höhere Anforderungen an das Erlebnis von Websites und Anwendungen stellen, müssen Frontend-Entwickler effizientere und flexiblere Tools verwenden, um reaktionsfähige und interaktive Schnittstellen zu erstellen. Als zwei wichtige Technologien im Bereich der Front-End-Entwicklung können PHP und Vue.js in Kombination als perfekte Waffe bezeichnet werden. In diesem Artikel geht es um die Kombination von PHP und Vue sowie um detaillierte Codebeispiele, die den Lesern helfen sollen, diese beiden besser zu verstehen und anzuwenden
Häufig gestellte Fragen von Front-End-Interviewern Mar 19, 2024 pm 02:24 PM
In Front-End-Entwicklungsinterviews decken häufige Fragen ein breites Themenspektrum ab, darunter HTML/CSS-Grundlagen, JavaScript-Grundlagen, Frameworks und Bibliotheken, Projekterfahrung, Algorithmen und Datenstrukturen, Leistungsoptimierung, domänenübergreifende Anfragen, Front-End-Engineering, Designmuster sowie neue Technologien und Trends. Interviewerfragen sollen die technischen Fähigkeiten, die Projekterfahrung und das Verständnis des Kandidaten für Branchentrends beurteilen. Daher sollten Kandidaten in diesen Bereichen umfassend vorbereitet sein, um ihre Fähigkeiten und Fachkenntnisse unter Beweis zu stellen.
Einfaches JavaScript-Tutorial: So erhalten Sie den HTTP-Statuscode Jan 05, 2024 pm 06:08 PM
JavaScript-Tutorial: So erhalten Sie HTTP-Statuscode. Es sind spezifische Codebeispiele erforderlich. Vorwort: Bei der Webentwicklung ist häufig die Dateninteraktion mit dem Server erforderlich. Bei der Kommunikation mit dem Server müssen wir häufig den zurückgegebenen HTTP-Statuscode abrufen, um festzustellen, ob der Vorgang erfolgreich ist, und die entsprechende Verarbeitung basierend auf verschiedenen Statuscodes durchführen. In diesem Artikel erfahren Sie, wie Sie mit JavaScript HTTP-Statuscodes abrufen und einige praktische Codebeispiele bereitstellen. Verwenden von XMLHttpRequest
Ist Django Front-End oder Back-End? Hör zu! Jan 19, 2024 am 08:37 AM
Django ist ein in Python geschriebenes Webanwendungs-Framework, das Wert auf schnelle Entwicklung und saubere Methoden legt. Obwohl Django ein Web-Framework ist, müssen Sie zur Beantwortung der Frage, ob Django ein Front-End oder ein Back-End ist, ein tiefes Verständnis der Konzepte von Front-End und Back-End haben. Das Front-End bezieht sich auf die Schnittstelle, mit der Benutzer direkt interagieren, und das Back-End bezieht sich auf serverseitige Programme. Sie interagieren mit Daten über das HTTP-Protokoll. Wenn das Front-End und das Back-End getrennt sind, können die Front-End- und Back-End-Programme unabhängig voneinander entwickelt werden, um Geschäftslogik bzw. interaktive Effekte sowie den Datenaustausch zu implementieren.
Ausgewählte Java JPA-Interviewfragen: Testen Sie Ihre Beherrschung des Persistenz-Frameworks Feb 19, 2024 pm 09:12 PM
Was ist JPA? Wie unterscheidet es sich von JDBC? JPA (JavaPersistence API) ist eine Standardschnittstelle für objektrelationales Mapping (ORM), die es Java-Entwicklern ermöglicht, vertraute Java-Objekte zum Betreiben von Datenbanken zu verwenden, ohne SQL-Abfragen direkt in die Datenbank schreiben zu müssen. JDBC (JavaDatabaseConnectivity) ist die Standard-API von Java für die Verbindung mit Datenbanken. Sie erfordert, dass Entwickler SQL-Anweisungen verwenden, um die Datenbank zu betreiben. JPA kapselt JDBC, bietet eine bequemere und übergeordnete API für die objektrelationale Zuordnung und vereinfacht Datenzugriffsvorgänge. Was ist in JPA eine Entität? juristische Person
Erkundung der Front-End-Technologie der Go-Sprache: eine neue Vision für die Front-End-Entwicklung Mar 28, 2024 pm 01:06 PM
Als schnelle und effiziente Programmiersprache erfreut sich Go im Bereich der Backend-Entwicklung großer Beliebtheit. Allerdings assoziieren nur wenige Menschen die Go-Sprache mit der Front-End-Entwicklung. Tatsächlich kann die Verwendung der Go-Sprache für die Front-End-Entwicklung nicht nur die Effizienz verbessern, sondern Entwicklern auch neue Horizonte eröffnen. In diesem Artikel wird die Möglichkeit der Verwendung der Go-Sprache für die Front-End-Entwicklung untersucht und spezifische Codebeispiele bereitgestellt, um den Lesern ein besseres Verständnis dieses Bereichs zu erleichtern. In der traditionellen Frontend-Entwicklung werden häufig JavaScript, HTML und CSS zum Erstellen von Benutzeroberflächen verwendet
Kombination von Golang- und Front-End-Technologie: Entdecken Sie, welche Rolle Golang im Front-End-Bereich spielt Mar 19, 2024 pm 06:15 PM
Kombination von Golang und Front-End-Technologie: Um zu untersuchen, welche Rolle Golang im Front-End-Bereich spielt, sind spezifische Codebeispiele erforderlich. Mit der rasanten Entwicklung des Internets und mobiler Anwendungen ist die Front-End-Technologie immer wichtiger geworden. Auch in diesem Bereich kann Golang als leistungsstarke Back-End-Programmiersprache eine wichtige Rolle spielen. In diesem Artikel wird untersucht, wie Golang mit Front-End-Technologie kombiniert wird, und sein Potenzial im Front-End-Bereich anhand spezifischer Codebeispiele demonstriert. Die Rolle von Golang im Front-End-Bereich ist effizient, prägnant und leicht zu erlernen
So erhalten Sie auf einfache Weise HTTP-Statuscode in JavaScript Jan 05, 2024 pm 01:37 PM
Einführung in die Methode zum Abrufen des HTTP-Statuscodes in JavaScript: Bei der Front-End-Entwicklung müssen wir uns häufig mit der Interaktion mit der Back-End-Schnittstelle befassen, und der HTTP-Statuscode ist ein sehr wichtiger Teil davon. Das Verstehen und Abrufen von HTTP-Statuscodes hilft uns, die von der Schnittstelle zurückgegebenen Daten besser zu verarbeiten. In diesem Artikel wird erläutert, wie Sie mithilfe von JavaScript HTTP-Statuscodes erhalten, und es werden spezifische Codebeispiele bereitgestellt. 1. Was ist ein HTTP-Statuscode? HTTP-Statuscode bedeutet, dass der Dienst den Dienst anfordert, wenn er eine Anfrage an den Server initiiert
- Standardverwendung von
- Wie aus dem obigen Bild ersichtlich ist, wurden die Eigenschaften des Objekts neu zugewiesen, während die Variable einen Typfehler von
- Nachdem der Befehl
const p = new Promise((resolve, reject) => { resolve(777); }); const result = await p; console.log(result); // 777正常输出
Nach dem Login kopierenNach dem Login kopieren - Normalerweise ist die von
- Natürlich kann man es auch in folgender Form schreiben: 🎜🎜
- Grundform des Exports: 🎜🎜
- 🎜Die Modulfunktion besteht hauptsächlich aus zwei Befehlen:
- 🎜