従うモジュール仕様は異なります
require/exports はワイルド仕様で生まれました。ワイルド仕様とは何ですか? つまり、これらの仕様は JavaScript コミュニティの開発者によって起草されたルールであり、誰もが認識している、または広く使用されているものです。CommonJS、AMD、CMD など。インポート/エクスポートはまともなものです。TC39 で指定された新しい ECMAScript バージョン、ES6 (ES2015) に含まれています。仕様と実装定義から、require は動的ロード、import は静的ロードです。基礎となる操作の観点から見ると、require はプログラムの実行時に解析され、import はリクエスト パッケージのコンパイル時に解析されます。require は全体をリクエストします。パッケージ オブジェクトとインポートは、必要なモジュールの要求された部分のみを要求します。現時点では import は ES6 の構文仕様としか考えられず、babel でパッケージ化した場合には require と本質的には変わらないはずです。
Vue または React で import と require の両方を使用できるのはなぜですか?
vue または React で import コマンドを使用し、エラーを報告せずに Node.js 経由でローカル サーバーを起動できる理由は、vue が babel を使用して ES6 モジュール システムをコンパイルし、それを CommonJS に変換して最新バージョンを標準化しているためです
。はモジュール仕様として CommonJS を使用しているため、ES6 モジュールシステムを使用したい場合は、当面は babel が必要です。
いくつかの具体的な違い
CommonJS
1. 基本データ型の場合はコピーです。つまり、モジュールによってキャッシュされます。同時に、このモジュールによって出力された変数を別のモジュールで再割り当てすることができます。
// b.js
let count = 1
let plusCount = () => {
count++
}
setTimeout(() => {
console.log('b.js-1', count)
}, 1000)
module.exports = {
count,
plusCount
}
// a.js
let mod = require('./b.js')
console.log('a.js-1', mod.count)
mod.plusCount()
console.log('a.js-2', mod.count)
setTimeout(() => {
mod.count = 3
console.log('a.js-3', mod.count)
}, 2000)
node a.js
a.js-1 1
a.js-2 1
b.js-1 2 // 1秒后
a.js-3 3 // 2秒后
上記のコードからわかるように、モジュール b によってエクスポートされた count 変数はコピー動作です。plusCount メソッドが呼び出された後、モジュール内のカウントは影響を受けません。同時に、モジュール a の値をモジュール b で変更することができます。コードを同期したい場合は、ゲッターをエクスポートできます。
// 其他代码相同
module.exports = {
get count () {
return count
},
plusCount
}
node a.js
a.js-1 1
a.js-2 1
b.js-1 2 // 1秒后
a.js-3 2 // 2秒后, 由于没有定义setter,因此无法对值进行设置。所以还是返回2
2. 複雑なデータ型の場合、これは浅いコピーです。2 つのモジュールによって参照されるオブジェクトは同じメモリ空間を指しているため、モジュールの値を変更すると、もう一方のモジュールに影響します。
// b.js
let obj = {
count: 1
}
let plusCount = () => {
obj.count++
}
setTimeout(() => {
console.log('b.js-1', obj.count)
}, 1000)
setTimeout(() => {
console.log('b.js-2', obj.count)
}, 3000)
module.exports = {
obj,
plusCount
}
// a.js
var mod = require('./b.js')
console.log('a.js-1', mod.obj.count)
mod.plusCount()
console.log('a.js-2', mod.obj.count)
setTimeout(() => {
mod.obj.count = 3
console.log('a.js-3', mod.obj.count)
}, 2000)
node a.js
a.js-1 1
a.js-2 2
b.js-1 2
a.js-3 3
b.js-2 3
上記のコードからわかるように、これはオブジェクトの浅いコピーです。モジュールが実行されると、obj.count の値は最初に 1 として出力され、次に plusCount メソッドを通じて再び 2 として出力されます。次に、モジュール a の count の値を 3 に変更します。このとき、モジュール b の値も 3 になります。
3. require コマンドを使用してモジュールがロードされると、モジュール全体のコードが実行されます。
4. require コマンドを使用して同じモジュールをロードする場合、モジュールは再度実行されませんが、キャッシュ内の値は取得されます。つまり、CommonJS モジュールは何度ロードされても、最初にロードされたときに 1 回だけ実行され、後でロードされた場合は、システム キャッシュがない限り、最初の実行の結果が返されます。手動でクリアされます。
5. ループでロードする場合、ロード中に実行されます。つまり、スクリプト コードが必要な場合は、すべて実行されます。モジュールを「ループロード」すると、実行された部分のみが出力され、未実行の部分は出力されません。
3、4、5は同じ例で説明できます
// b.js
exports.done = false
let a = require('./a.js')
console.log('b.js-1', a.done)
exports.done = true
console.log('b.js-2', '执行完毕')
// a.js
exports.done = false
let b = require('./b.js')
console.log('a.js-1', b.done)
exports.done = true
console.log('a.js-2', '执行完毕')
// c.js
let a = require('./a.js')
let b = require('./b.js')
console.log('c.js-1', '执行完毕', a.done, b.done)
node c.js
b.js-1 false
b.js-2 执行完毕
a.js-1 true
a.js-2 执行完毕
c.js-1 执行完毕 true true
全体のプロセスを詳しく説明します。
- Node.jsでcモジュールを実行します。このとき、require キーワードが検出され、a.js 内のすべてのコードが実行されます。
- モジュール a でエクスポートした後、require を通じてモジュール b が導入され、モジュール b のコードが実行されます。
- モジュール b のエクスポート後、require 経由でモジュール a が導入され、この時点でモジュール a のコードが実行されます。
- モジュール a はステートメント exports.done = false のみを実行します。
- モジュール b に戻り、b.js-1、exports、b.js-2 を出力します。モジュール b が実行されます。
- モジュール a に戻り、a.js-1、exports、b.js-2 を出力します。モジュールaが実行される
- c モジュールに戻り、require を実行して、b モジュールを導入する必要があります。モジュールaで導入されているので、値を直接出力することができます。
- 仕上げる。
上記の結果と分析プロセスから、require コマンドに遭遇すると、対応するモジュール コードが実行されることがわかります。循環参照が発生した場合、モジュールのコードの一部のみを出力する可能性があります。同じモジュールが参照される場合、そのモジュールは再度ロードされず、キャッシュされます。
ES6モジュール
1. es6 モジュール内の値は [動的読み取り専用参照] に属します。複雑なデータ型について説明するだけです。
2. 読み取り専用の場合、インポートされた変数の値は変更できません。インポートされた変数は、基本データ型であるか複合データ型であるかにかかわらず、読み取り専用です。モジュールがインポート コマンドに遭遇すると、読み取り専用の参照が生成されます。スクリプトが実際に実行されると、この読み取り専用参照に基づいて、ロードされたモジュールから値が取得されます。
3. ダイナミクスの場合、元の値が変更されると、インポートによって読み込まれる値も変更されます。基本データ型であるか、複雑なデータ型であるか。
// b.js
export let counter = {
count: 1
}
setTimeout(() => {
console.log('b.js-1', counter.count)
}, 1000)
// a.js
import {
counter } from './b.js'
counter = {
}
console.log('a.js-1', counter)
// Syntax Error: "counter" is read-only
カウンタを新しいオブジェクトに再割り当てすることはできませんが、プロパティとメソッドをオブジェクトに追加することはできます。現時点ではエラーは報告されません。このタイプの動作は、キーワード const の使用法と一致します。
// a.js
import {
counter } from './b.js'
counter.count++
console.log(counter)
// 2
4. ループでロードすると、ES6 モジュールが動的に参照されます。2 つのモジュール間に何らかの参照が存在する限り、コードは実行できます。
// b.js
import {
foo} from './a.js';
export function bar() {
console.log('bar');
if (Math.random() > 0.5) {
foo();
}
}
// a.js
import {
bar} from './b.js';
export function foo() {
console.log('foo');
bar();
console.log('执行完毕');
}
foo();
babel-node a.js
foo
bar
执行完毕
// 执行结果也有可能是
foo
bar
foo
bar
执行完毕
执行完毕
両方のモジュール間に参照があるためです。したがって、正常に実行できます。