モジュールの構文
1 はじめに
ES6 以前は、主に と の 2 種類がありましCommonJS
たAMD
。サーバーには CommonJS、ブラウザには AMD。ES6 は言語標準レベルでモジュール機能を実装しており、その実装は非常にシンプルで、CommonJS や AMD の仕様を完全に置き換えて、ブラウザとサーバーの共通モジュール ソリューションとなります。大統一段階に入った。
ES6 モジュールの設計思想は、可能な限り静的であることです。コンパイル時間モジュールの依存関係だけでなく、入力変数と出力変数も確認できます。CommonJS モジュールと AMD モジュールは両方とも、以下でのみ使用できます。ランタイムこれらのことを確認してください。
// CommonJS模块
let {
stat, exists, readfile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
この種の読み込みは「実行時読み込み」と呼ばれます。これは、このオブジェクトは実行時にのみ取得できるため、コンパイル時に「静的最適化」を行うことができないためです。
ES6 モジュールはオブジェクトではなく、コマンドによるexport
出力とコマンドによる入力を明示的に指定するコードですimport
。
// ES6模块
import {
stat, exists, readFile } from 'fs';
上記のコードの本質は、fs モジュールから 3 つのメソッドをロードすることであり、他のメソッドはロードされません。この読み込みは、「コンパイル時読み込み」または静的読み込みと呼ばれます。つまり、ES6 はコンパイル時にモジュールの読み込みを完了でき、CommonJS モジュールの読み込みよりも効率的です。もちろん、ES6 モジュール自体はオブジェクトではないため、これにより ES6 モジュール自体を参照することもできなくなります。
2.ストリクトモード
ES6 モジュールは、モジュール ヘッダーに追加するかどうかに関係なく、厳密モードを自動的に採用します"use strict"
。
Strict モードには主に以下の制限があります。
- 変数は使用する前に宣言する必要があります
- 関数のパラメータに同じ名前の属性を含めることはできません。そうでない場合は、エラーが報告されます。
- with ステートメントは使用できません
- 読み取り専用属性に値を割り当てることはできません。割り当てないとエラーが報告されます。
- 削除できない属性は削除できません。削除しないとエラーが報告されます。
- 変数は削除できません
delete prop
。エラーが報告されます。削除できるのは属性のみです。delete global[prop]
eval
外部スコープに変数を導入しませんeval
arguments
再割り当てはできませんarguments
関数パラメータの変更は自動的に反映されません- 故障中
arguments.callee
- 故障中
arguments.caller
this
グローバルオブジェクトを指さないでください- 関数呼び出しのスタックを使用
fn.caller
および取得できないfn.arguments
- 予約語(
protected
、static
、 などinterface
)を追加しました。
3. エクスポートコマンド
モジュール関数は主に と の 2 つのコマンドで構成されexport
ますimport
。export
コマンドはモジュールの外部インターフェースを指定するために使用され、import
コマンドは他のモジュールが提供する機能を入力するために使用されます。
モジュールは単一のファイルです。ファイル内のすべての変数を外部から取得することはできません。モジュール内の変数を外部から読み取れるようにしたい場合は、export
キーワードを使用して変数を出力する必要があります。以下はコマンド出力変数を使用する JS ファイルですexport
。
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
// 另一种写法
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {
firstName, lastName, year };
export
コマンドは変数を出力するだけでなく、関数やクラスを出力することもできます。
export function multiply(x, y) {
return x * y;
};
上記のコードは関数を外部に出力しますmultiply
。
通常、export
出力変数は元の名前ですが、as
キーワードを使用して名前を変更できます。
function v1() {
... }
function v2() {
... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
特に注意が必要なのは、export
コマンドが外部インターフェイスを指定しており、モジュール内の変数と 1 対 1 の対応を確立する必要があることです。
// 报错
export 1;
// 报错
var m = 1;
export m;
上記 2 つの書き方では、外部インターフェイスが提供されていないため、エラーが報告されます。1 つ目の書き方は直接出力する方法1
、2 つ目の書き方は変数を介してm
直接出力する方法です1
。1
インターフェイスではなく、単なる値です。正しい書き方は以下の通りです。
// 写法一
export var m = 1;
// 写法二
var m = 1;
export {
m};
// 写法三
var n = 1;
export {
n as m};
外部インターフェース m を指定する上記 3 つの記述方法はすべて正しいです。他のスクリプトは、このインターフェイスを通じて値 1 を取得できます。それらの本質は、インターフェイス名とモジュールの内部変数の間に 1 対 1 の対応を確立することです。
同様に、function
との出力もclass
この書き方に従う必要があります。
// 报错
function f() {
}
export f;
// 正确
export function f() {
};
// 正确
function f() {
}
export {
f};
4.インポートコマンド
コマンドを使用してexport
モジュールの外部インターフェイスを定義した後、他の JS ファイルはimport
コマンドを通じてこのモジュールをロードできます。
// main.js
import {
firstName, lastName, year } from './profile.js';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
入力変数の名前を変更する場合、import
コマンドはas
キーワードを使用して入力変数の名前を変更する必要があります。
import {
lastName as surname } from './profile.js';
import
コマンドの本質は入力インターフェイスであるため、コマンドによって入力される変数はすべて読み取り専用です。つまり、モジュールをロードするスクリプト内のインターフェイスを書き換えることはできません。
import {
a} from './xxx.js'
a = {
}; // Syntax Error : 'a' is read-only;
上記のコードでは、スクリプトは変数 をロードしますa
。変数が再割り当てされると、 a は読み取り専用インターフェイスであるため、エラーが報告されます。ただし、a
オブジェクトの場合は、a
プロパティのオーバーライドが許可されます。
import {
a} from './xxx.js'
a.foo = 'hello'; // 合法操作
5. モジュールの全体的なロード
特定の出力値をロードするように指定することに加えて、全体的なロード、つまりアスタリスク (*) を使用してオブジェクトを指定することもでき、すべての出力値がこのオブジェクトにロードされます。
以下は、エリアと円周の 2 つのメソッドをエクスポートする Circle.js ファイルです。
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
次に、このモジュールをロードします。
// main.js
import {
area, circumference } from './circle';
console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));
上記はロードするメソッドを一つずつ指定する方法で、全体のロード方法は以下の通りです。
import * as circle from './circle';
console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));
モジュールが全体としてロードされるオブジェクト (上の例では円) は静的に分析可能である必要があるため、実行時の変更は許可されないことに注意してください。以下の書き込みは禁止です。
import * as circle from './circle';
// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {
};
6. デフォルトコマンドのエクスポート
このコマンドを使用するときimport
、ユーザーはロードする変数または関数の名前を知っている必要があります。そうでないと、ロードできません。ただし、ユーザーは間違いなくすぐに使い始めたいと考えており、ドキュメントを読みたがらない可能性があります。したがって、便宜上、このコマンドはexport default
モジュールのデフォルト出力を指定するために使用されます。
// export-default.js
export default function () {
console.log('foo');
}
上記のコードはモジュール ファイルでありexport-default.js
、そのデフォルトの出力は関数です。
他のモジュールがこのモジュールをロードするとき、import
コマンドは匿名関数に任意の名前を指定できます。
// import-default.js
import customName from './export-default';
customName(); // 'foo'
上記コードのコマンドでは、出力メソッドをimport
指す任意の名前を使用できますが、この時点では、元のモジュールが出力する関数名を知る必要はありません。現時点ではコマンドの後に中括弧が使用されていないexport-default.js
ことに注意してください。import
export default
非匿名関数の前にコマンドを使用することもできます。
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
上記のコードでは、foo
関数の関数名がfoo
モジュール外では無効です。ロード時は無名関数ロードとみなされます。
// 第一组
export default function crc32() {
// 输出
// ...
}
import crc32 from 'crc32'; // 输入
// 第二组
export function crc32() {
// 输出
// ...
};
import {
crc32} from 'crc32'; // 输入
上記の 2 つのグループのコードが記述されており、最初のグループは使用されexport default
、対応するステートメントは中括弧を使用するimport
必要がありません。2 番目のグループは使用されずexport default
、対応するimport
ステートメントは中括弧を使用する必要があります。
exportdefault コマンドは、モジュールのデフォルト出力を指定するために使用されます。明らかに、モジュールはデフォルト出力を 1 つしか持つことができないため、exportdefault コマンドは 1 回しか使用できません。したがって、インポート コマンドの後に中括弧を使用する必要はありません。これは、エクスポート デフォルト コマンドにのみ対応できるためです。
本質的には、という名前の変数またはメソッドexport default
をエクスポートすることでありdefault
、システムではそれに任意の名前を付けることができます。したがって、次の記述は有効です。
// modules.js
function add(x, y) {
return x * y;
}
export {
add as default};
// 等同于
// export default add;
// app.js
import {
default as foo } from 'modules';
// 等同于
// import foo from 'modules';
7. エクスポートとインポートの複合記述
モジュール内で、同じモジュールが最初に入力され、次に出力される場合、import
ステートメントをexport
ステートメントと一緒に記述することができます。
export {
foo, bar } from 'my_module';
// 可以简单理解为
import {
foo, bar } from 'my_module';
export {
foo, bar };
上記のコードでは、export
ANDimport
ステートメントを結合して 1 行に記述することができます。foo
ただし、と は1 行で記述された後、bar
実際には現在のモジュールにインポートされるのではなく、これら 2 つのインターフェイスを外部に転送するのと同等であるため、現在のモジュールはfoo
と を直接使用できないことに注意してくださいbar
。
インターフェイスの名前変更とモジュールの全体的な出力もこの方法で記述することができます。
// 接口改名
export {
foo as myFoo } from 'my_module';
// 整体输出
export * from 'my_module';
デフォルトのインターフェースは次のように書かれています。
export {
default } from 'foo';
名前付きインターフェースをデフォルトインターフェースに変更する記述方法は以下のとおりです。
export {
es6 as default } from './someModule';
// 等同于
import {
es6 } from './someModule';
export default es6;
同様に、デフォルトのインターフェースの名前を名前付きインターフェースに変更することもできます。
export {
default as es6 } from './someModule';
ES2020以前はimport文はありましたが、対応する複合記述方法はありませんでした。
import * as someIdentifier from "someModule";
ES2020ではこの書き方が追加されました。
export * as ns from "mod";
// 等同于
import * as ns from "mod";
export {
ns};