И в ES6, и в CommonJS есть собственный набор мер для работы с модульным кодом, а именно взаимные ссылки между файлами JS.
Чтобы облегчить два метода тестирования, используйте среду nodejs для тестирования.
Работа с модулями в CommonJS
Используйте require для импорта кода из других модулей и используйте module.exports для экспорта.
// exportDemo.js
count = 1;
module.exports.count = count;
module.exports.Hello = function() {
var name;
this.setName = function(newName) {
name = newName;
}
this.sayHello = function() {
console.log("hello Mr." + name);
}
this.getId = function() {
return count++
}
}
// requireDemo.js
var {Hello} = require("./exportDemo")
var hello = new Hello();
hello.setName("Blank");
hello.sayHello();
выполнить в терминалеnode requireDemo.js
, возвращаемый результат - "привет, мистер Бланк"
Экспортированная функция Hello является копией исходной функции. Изменение значения атрибута функции Hello не повлияет на другие требуемые места.
var { Hello, count } = require('./exportDemo')
var hello = new Hello();
// 让count自增
console.log(hello.getId());
console.log(hello.getId());
// 发现获取的count还是原值
console.log(count)
// 真正的count其实是已经改了的
var newHello = new Hello();
console.log(newHello.getId())
var { Hello: newHello, count: newCount } = require('./exportDemo')
console.log(newCount, 'newCount');
// 再次require,取得的newHello和之前require的Hello指向同一个拷贝
console.log(newHello === Hello)
Обработка модулей в ES6
Запуск кода в стиле ES6 в nodejs
Nodejs по умолчанию не поддерживает схему обработки модулей ES6.
Но после 8.5.0, после того как формат файла кода ES6 установлен на mjs, вы можете использоватьnode --experimental-modules xxx.mjs
бегать.
// exportDemo.mjs
export let a = 1;
// importDemo.mjs
import {a} from './exportDemo.mjs'
console.log(a)
Различия в обработке модуля CommonJS
-
Модули CommonJS выводят копию значения (проверено в предыдущей главе), а модули ES6 выводят ссылку на значение.
// exportDemo.mjs export let counter = 1; export function incCounter() { counter ++; }
// importDemo.mjs import { counter, incCounter } from './exportDemo.mjs' incCounter(); console.log(counter) // 打印结果为2,而不是初始值的1
-
Модули CommonJS загружаются во время выполнения, модули ES6 являются выходными интерфейсами во время компиляции.
-
Среды выполнения, такие как Nodejs, будут запускать код модуля CommonJS в замыкании.
(function(exports, require, module, __filename, __dirname) { // Module code actually lives in here });
-
Модули ES6 не кэшируют результаты, а динамически извлекают значения из загруженных модулей, а переменные всегда привязаны к тому модулю, в котором они находятся.
// exportDemo.mjs export let a = 1; export const b = 2; export let obj = {}; // importDemo.mjs import { a, b } from './exportDemo.mjs' console.log(a, b) a = 1 // 报错,TypeError: Assignment to constant variable,export出来的值是一个只读引用 obj.x = 1 // 可以改变属性值
В модулях ES6 мы должны больше думать о синтаксисе.
-
export default
Иногда мы найдем в кодеexport default obj
использование, то для чего используется это значение по умолчанию?
default — это ключевое слово, введенное в ES6 и используемое вместе с export, для установки имени по умолчанию для анонимных объектов и анонимных функций.
Экспортируемое значение должно иметь имя, иначе будет сообщено об ошибке на грамматическом уровне.
Давайте рассмотрим следующие примеры ошибок, которые вызовут ошибку
-
экспортировать анонимные объекты
export { x: 1 } // 报错,SyntaxError:Unexpected token,这是一个编译阶段的错误 // 正确写法 export default { x: 1 }
-
экспортировать анонимную функцию
export function() {} // 报错,SyntaxError: Unexpected token ( // 正确写法 export default function() {}
Переработка загрузки
В сложных модулях могут быть межмодульныессылаться друг на друга.
Циклический механизм работы ссылок commonJS
// a.js
exports.loaded = false;
var b = require('./b.js')
console.log("b in a is " + JSON.stringify(b))
exports.loaded = true;
console.log("a complete")
// b.js
exports.loaded = false;
var a = require('./a.js')
console.log("a in b is " + JSON.stringify(a))
exports.loaded = true;
console.log("b complete")
// main.js
var a = require('./a.js')
var b = require('./b.js')
console.log("a in main is" + JSON.stringify(a))
console.log("b in main is" + JSON.stringify(b))
Выполнить инструкцииnodejs main.js
Покомпонентное представление шагов выполнения на диаграмме последовательности выглядит следующим образом:
Циклический эталонный рабочий механизм ES6
- Пример ошибки
// a.mjs
import { bar } from './b.mjs'
console.log(bar);
export let foo = 'foo from a.mjs'
// b.mjs
import { foo } from './a.mjs'
console.log(foo)
export let bar = 'bar from b.mjs'
// main.mjs
import { foo } from './a.mjs'
import { bar } from './b.mjs'
node main.mjs
Покомпонентное представление шагов выполнения на диаграмме последовательности выглядит следующим образом:
В циклических ссылках ES6 следует обращать особое внимание на то, объявлена ли переменная.Если на необъявленную переменную блочной области ссылаются другие модули, будет сообщено об ошибке.
-
План улучшения: попробуйте экспортировать значения, которые можно определить заранее (например, функции) в циклических ссылках.На самом деле, мы всегда хотим перейти кПеременные, которые дорабатываются после полного выполнения эталонного модуля.
// a.mjs import { bar } from './b.mjs' console.log(bar()); export function foo() { return 'foo from a.mjs' }
// b.mjs import { foo } from './a.mjs' console.log(foo()); export function bar() { return 'bar from b.mjs' }
// main.mjs import { foo } from './a.mjs' import { bar } from './b.mjs'
node main.mjs
Возвращаемый результат:
foo from a.mjs bar from b.mjs
Покомпонентное представление шагов выполнения на диаграмме последовательности выглядит следующим образом: