CommonJs
には多くの優れた機能があります。以下で簡単にレビューしてみましょう:
モジュール コードは、次の場合にのみロードされます。実行中;
Es module
この非同期再帰読み込みプロセスは、アプリケーション全体の依存関係グラフが解決されるまで続行されます。依存関係グラフが解析された後、参照プログラムはモジュールを正式にロードできます。
Es Module
は、CommonJs と
AMD の多くの優れた機能を借用するだけでなく、いくつかの新しい動作も追加します。
Es モジュール
##Es モジュール
グローバル名前空間を共有しません;
Es Module
最上位の
です (通常のスクリプトは window
です) );var
モジュール内の宣言は
Es Module
は非同期でロードおよび実行されます。
エクスポートとインポート
export
コマンドはモジュールの外部インターフェイスを指定するために使用され、
import
#エクスポートの基本的な使用法
エクスポートの基本形式: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 };
const address = "广州"; const age = 18; export { nickname as name, address as where, age as old };
デフォルトのエクスポート。モジュールはデフォルトのエクスポートを 1 つだけ持つことができることに注意してください:
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">export default "foo";
export default { name: &#39;moment&#39; }
export default function foo(x,y) {
return x+y
}
export { bar, foo as default };</pre><div class="contentsignin">ログイン後にコピー</div></div>
if(true){
export {...};
}
// 1只是一个值,不是一个接口 export 1 // moment只是一个值为1的变量 const moment = 1 export moment // function和class的输出,也必须遵守这样的写法 function foo(x, y) { return x+y } export foo
コマンドでモジュールの外部インターフェイスを定義した後、他の js ファイルは import コマンドを通じてモジュール全体をロードできます。
import {foo,age,nickname} form '模块标识符'
import コマンドは、他のモジュールからインポートされる変数名を指定する中括弧を受け入れます。変数名は、インポートされたモジュールの外部インターフェイスの名前と同じである必要があります。モジュール。
上の図からわかるように、オブジェクトのプロパティは再割り当てされ、変数は 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";
dynamic import
import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment });
を使用して取得することもできます。
import インポートされたモジュールは静的であるため、ロード時にインポートされたすべてのモジュールがコンパイルされます (オンデマンドでのコンパイルは達成できないため、モジュールのロード速度が低下します)。ホームページ)。シナリオによっては、条件に基づいて、またはオンデマンドでモジュールをインポートする必要がある場合があります。この場合、静的インポートの代わりに動的インポートを使用できます。 キーワード import
関数を呼び出すのと同じように、モジュールを動的にインポートできます。このように呼び出すと、
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);
トップレベルの await を使用する
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);
Top-level await
:const p = new Promise((resolve, reject) => { resolve(777); }); const result = await p; console.log(result); // 777正常输出
import 的错误使用
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'; }
在浏览器上,你可以通过将 type
属性设置为 module
用来告知浏览器将 script
标签视为模块。
<script type="module" src="./main.mjs"></script> <script type="module"></script>
defer
的方式延迟你的 nomodule
脚本:<script type="module"> console.log("模块情况下的"); </script> <script src="./main.js" type="module" defer></script> <script> console.log("正常 script标签"); </script>
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>
默认情况下,nomodule
脚本会阻塞 HTML
解析。你可以通过添加 defer
属性来解决此问题,该属性是等到 HTML
解析完成之后才执行。
defer
和 async
是一个可选属性,他们只可以选择其中一个,在 nomodule
脚本下,defer
等到 HTML
解析完才会解析当前脚本,而 async
会和 HTML
并行解析,不会阻塞 HTML
的解析,模块脚本可以指定 async
属性,但对于 defer
无效,因为模块默认就是延迟的。async
属性,模块脚本及其所有依赖项将于解析并行获取,并且模块脚本将在它可用时进行立即执行。讨论 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
是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
在学习工作原理之前,我们不妨来认识一下相关的概念。
Module Record
模块记录(Module Record
) 封装了关于单个模块(当前模块)的导入和导出的结构信息。此信息用于链接连接模块集的导入和导出。一个模块记录包括四个字段,它们只在执行模块时使用。其中这四个字段分别是:
Realm
: 创建当前模块的作用域;
Environment
:模块的顶层绑定的环境记录,该字段在模块被链接时设置;
Namespace
: モジュール名前空間オブジェクトは、モジュール エクスポート バインディングへの実行時のプロパティベースのアクセスを提供するモジュール名前空間外部オブジェクトです。モジュール名前空間オブジェクトにはコンストラクターがありません;
HostDefined
: ホスト環境
で使用するために予約されたフィールド、追加情報を関連付ける必要がありますモジュール 。
#モジュール環境レコード
バインディングも提供します。
不変バインディングとは、現在のモジュールが他のモジュールを導入し、導入された変数は変更できないことを意味します。これは、モジュール固有の不変バインディングです。
Construction)、アドレスに従って
js ファイルを見つけ、ネットワーク経由でダウンロードします。モジュール ファイルは
Module Record;
Instantiation) で、モジュールをインスタンス化し、メモリ領域を割り当てます。モジュールのインポートおよびエクスポート ステートメントを解析し、モジュールが対応するメモリ アドレスを指すようにします。
評価)、コードの実行、計算値、および値がメモリ アドレスに埋め込まれます。
#建設建設フェーズ
モジュールのアドレス指定とダウンロードを担当します。まずエントリ ファイルを変更します。これは通常、
HTML ではモジュール ファイルを表す
タグです。
ステートメントを通じて宣言され続けます。
import にはモジュール宣言識別子があります。 宣言ステートメント。文字 (
ModuleSpecifier)。
loader に次のモジュールのアドレスを見つける方法を指示します。
、および各
モジュール レコード# #に対応します。 #JavaScript コード
、実行コンテキスト
、ImportEntries
、LocalExportEntries
、IndirectExportEntries
、StarExportEntries ##が含まれます#。
ImportEntries 値は
ImportEntry Records タイプであり、
LocalExportEntries、
IndirectExportEntries、
StarExportEntries は
です。 ExportEntry Records タイプ。
、
ImportName が含まれています,
LocalName;
ModuleRequest: モジュール識別子 (ImportName: by
ModuleRequest
namespace-object は、インポート要求がターゲット モジュールの名前空間オブジェクトに対するものであることを示します。
LocalName: インポートされたモジュールから現在のモジュールのインポート値にアクセスするために使用される変数。
詳細については、以下の図を参照してください。
インポート名 (ImportName) | LocalName(LocalName) | ##"react"; | |||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
"React" | import * as Moment from "react"; | "react" | |||||||||||||||||||||||||||||||||||||||||||||||||||
"モーメント" | 「反応」から {useEffect} をインポート; | "反応" | |||||||||||||||||||||||||||||||||||||||||||||||||||
"useEffect" | 「react」から {useEffect をエフェクトとしてインポート }; | "react" | |||||||||||||||||||||||||||||||||||||||||||||||||||
###"効果"############ExportEntry Records
|