ホームページ > 記事 > ウェブフロントエンド > ES6モジュールの詳しい説明
現在、当社のプロジェクトはほぼすべてwebpackやrollupなどのビルドツールをベースに開発されており、モジュール化が主流となっています。
私たちもこれには馴染みがありませんが、今日は ES6 のモジュールの仕組みを体系的にレビューし、共通の操作とベスト プラクティスをまとめます。
簡単な背景
そのまま進めてください。これは私たち全員が実現を望んでいるメカニズムです。
JavaScript も同様で、大きな Javascript プログラムをいくつかの部分に分割し、どの部分を使用するか、その部分だけを取り出します。
[関連コースの推奨事項: JavaScript ビデオ チュートリアル ]
長い間、NodeJS にはそのような機能がありましたが、その後、ますます多くのライブラリやフレームワークが追加されました。 CommonJS などのモジュール化、または AMD モデルに基づく実装 (RequireJs など)、および後続の Webpack、Babel など。
2015 年までに、標準的なモジュラー システムが誕生しました。これが、今日お話しする主役である ES6 モデル システムです。
一見すると、ES6 モデル システムが CommonJS 構文に非常に似ていることがわかりますが、結局のところ、ES6 モデル システムは CommonJS 時代から生まれており、CommonJS の影響を深く受けています。
CommonJs などの簡単な例を見てください: (https://flaviocopes.com/commonjs/)
//file.js module.exports = value; // 引入value const value = require('file.js')
ES6 では:
// const.js export const value = 'xxx'; import { value } from 'const.js'
構文は次のとおりです。とても似ている。
以下では、ES6 モジュールについて詳しく知るために、主にインポートとエクスポート、およびいくつかの関連機能について説明します。
モジュール化のメリット
モジュール化の主なメリットは次の 2 点です。
1. 避免全局变量污染 2. 有效的处理依赖关系
時代の進化とともに, ブラウザーも es6 のインポートおよびエクスポート構文をネイティブにサポートし始めています。
まず簡単な例を見てみましょう:
<script> import { addTextToBody } from '/util.js'; addTextToBody('Modules are pretty cool.'); </script> // util.js export function addTextToBody(text) { const p = document.createElement('p'); p.textContent = text; document.body.appendChild(p); }
イベントを処理したい場合も同様です。簡単な例を見てみましょう:
<button>Show Message</button> <script></script> // showImport.js import { showMessage } from '/show.js' document.getElementById('test').onclick = function() { showMessage(); } // show.js export function showMessage() { alert("Hello World!") }
このデモを実行する場合は、必ず簡単なサービスをセットアップしてください:
$ http-server
そうしないと、CORS エラーが表示されます。
エラーの具体的な原因やその他の詳細については、この記事では取り上げませんので、興味のある方は以下のリンクを参照してください。
https://jakearchibald.com/2017/es-modules-in-browsers/
厳密モード
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
「use strict」ステートメントは私たちにとってよく知られたもので、es5 時代にはよく使用されていました。このステートメントをファイルの先頭に追加する目的は、JavaScript のあまりフレンドリーでない部分を無効にして、より厳密なコードを記述できるようにすることです。
この機能は、es6 構文ではデフォルトで有効になっています。コード内に厳密性の低いコードがある場合は、次のようなエラーが報告されます:
以下は、strict モード
で disabled
となっている一部の部分を MDN から抜粋したものです:
変数を未宣言のままにすることはできません
関数パラメータ
には一意の名前
が必要です(または構文エラーとみなされます)with
は禁止されています読み取り専用プロパティへの代入でエラーがスローされる
00840 のような 8 進数
は 構文エラーです
エラーをスローします
は、delete global[prop]
#eval
#arguments## にバインドしたり割り当てたりすることはできません #メソッド パラメータへの変更を魔法のように追跡します。arguments.callee
は TypeError をスローします (サポートされなくなりました)arguments.caller
は TypeError をスローします (サポートされなくなりました)
予約語
(例: protected、static、interface など) はバインドできません
ES6 モジュールは静的エクスポートのみをサポートしています。エクスポートはモジュールの最も外側のスコープでのみ使用できます。条件文や関数では使用できません。ドメインで使用されます。 分類に関しては、エクスポートには主に 3 つのタイプがあります:
1. 名前付きエクスポート (モジュールごとに 0 個以上のエクスポート)
2. デフォルトのエクスポート (モジュールごとに 1 つ) module)
3. ハイブリッド エクスポート
エクスポートの概要:// Exporting inpidual features export let name1, name2, …, nameN; // also var, const export let name1 = …, name2 = …, …, nameN; // also var, const export function functionName(){...} export class ClassName {...} // Export list export { name1, name2, …, nameN }; // Renaming exports export { variable1 as name1, variable2 as name2, …, nameN }; // Exporting destructured assignments with renaming export const { name1, name2: bar } = o; // Default exports export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … }; // Aggregating modules export * from …; // does not set the default export export * as name1 from …; export { name1, name2, …, nameN } from …; export { import1 as name1, import2 as name2, …, nameN } from …; export { default } from …;
次に、エクスポートの一般的な使用法を紹介します。 1. Named exports (导出每个函数/变量) 具名导出,这种方式导出多个函数,一般使用场景比如 utils、tools、common 之类的工具类函数集,或者全站统一变量等。 只需要在变量或函数前面加 我们也可以直接导出一个列表,例如上面的lib.js可以改写成: 2. Default exports (导出一个默认 函数/类) 这种方式比较简单,一般用于一个类文件,或者功能比较单一的函数文件使用。 一个模块中只能有一个export default默认输出。 export default与export的主要区别有两个: 不需要知道导出的具体变量名, 导入(import)时不需要{}. 导出一个类 注意这里默认导出不需要用{}。 3. Mixed exports (混合导出) 混合导出,也就是 上面第一点和第二点结合在一起的情况。比较常见的比如 Lodash,都是这种组合方式。 再比如lodash例子: 4. Re-exporting (别名导出) 一般情况下,export输出的变量就是在原文件中定义的名字,但也可以用 as 关键字来指定别名,这样做一般是为了简化或者语义化export的函数名。 5. Module Redirects (中转模块导出) 有时候为了避免上层模块导入太多的模块,我们可能使用底层模块作为中转,直接导出另一个模块的内容如下: import的几种用法 import的用法和export是一一对应的,但是import支持静态导入和动态导入两种方式,动态import支持晚一些,兼容性要差一些。 下面我就总结下import的基本用法: 1. Import All things 当export有多个函数或变量时,如文中export的第一点,可以使用 * as 关键字来导出所有函数及变量,同时 as 后面跟着的名称做为 该模块的命名空间。 2. Import a single/multiple export from a module 从模块文件中导入单个或多个函数,与 * as namepage 方式不同,这个是按需导入。如下例子: 3. Rename multiple exports during import 和 export 一样,也可以用 as 关键字来设置别名,当import的两个类的名字一样时,可以使用 as 来重设导入模块的名字,也可以用as 来简化名称。 4. Import a module for its side effects only 有时候我们只想import一个模块进来,比如样式,或者一个类库。 5. Dynamic Imports 静态import在首次加载时候会把全部模块资源都下载下来. 我们实际开发时候,有时候需要动态import(dynamic import)。 例如点击某个选项卡,才去加载某些新的模块: es7的新用法: 总结 以上, 我总结了ES6 Module 的简单背景和 常见的import , export 用法, 但这远远不是它的全部, 篇幅有限,如果想了解更多, 可以看下面的延伸阅读部分(质量都还不错, 可以看看)。 本文来自 js教程 栏目,欢迎学习!export
关键字即可。//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js 使用方式1 ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
//------ main.js 使用方式2 ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5
//------ lib.js ------
const sqrt = Math.sqrt;
function square(x) {
return x * x;
}
function add (x, y) {
return x + y;
}
export { sqrt, square, add }
//------ myFunc.js ------
export default function () {};
//------ main.js ------
import myFunc from 'myFunc';
myFunc();
//------ MyClass.js ------
class MyClass{}
export default MyClass;
//------ Main.js ------
import MyClass from 'MyClass';
//------ lib.js ------
export var myVar = ...;
export let myVar = ...;
export const MY_CONST = ...;
export function myFunc() {
// ...
}
export function* myGeneratorFunc() {
// ...
}
export default class MyClass {
// ...
}
// ------ main.js ------
import MyClass, { myFunc } from 'lib';
//------ lodash.js ------
export default function (obj) {
// ...
};
export function each(obj, iterator, context) {
// ...
}
export { each as forEach };
//------ main.js ------
import _, { forEach } from 'lodash';
//------ lib.js ------
export function getUserName(){
// ...
};
export function setName(){
// ...
};
//输出别名,在import的时候可以同时使用原始函数名和别名
export {
getName as get, //允许使用不同名字输出两次
getName as getNameV2,
setName as set
}
//------ myFunc.js ------
export default function() {...};
//------ lib.js ------
export * from 'myFunc';
export function each() {...};
//------ main.js ------
import myFunc, { each } from 'lib';
export 只支持在最外层静态导出、只支持导出变量、函数、类,如下的几种用法都是错误的。
`错误`的export用法:
//直接输出变量的值
export 'Mark';
// 未使用中括号 或 未加default
// 当只有一个导出数,需加default,或者使用中括号
var name = 'Mark';
export name;
//export不要输出块作用域内的变量
function () {
var name = 'Mark';
export { name };
}
//导出lib的所有函数及变量
import * as lib from 'lib';
//以 lib 做为命名空间进行调用,类似于object的方式
console.log(lib.square(11)); // 121
//导入square和 diag 两个函数
import { square, diag } from 'lib';
// 只导入square 一个函数
import { square } from 'lib';
// 导入默认模块
import _ from 'lodash';
// 导入默认模块和单个函数,这样做主要是简化单个函数的调用
import _, { each } from 'lodash';
比如:// 用 as 来 简化函数名称
import {
reallyReallyLongModuleExportName as shortName,
anotherLongModuleName as short
} from '/modules/my-module.js';
// 避免重名
import { lib as UserLib} from "alib";
import { lib as GlobalLib } from "blib";
// 导入样式
import './index.less';
// 导入类库
import 'lodash';
// 当动态import时,返回的是一个promise
import('lodash')
.then((lodash) => {
// Do something with lodash.
});
// 上面这句实际等同于
const lodash = await import('lodash');
async function run() {
const myModule = await import('./myModule.js');
const { export1, export2 } = await import('./myModule.js');
const [module1, module2, module3] =
await Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]);
}
run();
以上がES6モジュールの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。