У вас довольно хорошее понимание, но есть несколько аномалий, которые следует исправить.
ES Модули
В ECMA-262 все модули будут иметь такую общую форму:
Abstract Module {
Environment // Holds lexical environment for variables declared in module
Namespace // Exotic object that reaches into Environment to access exported values
Instantiate()
Evaluate()
}
Существует много разных мест, откуда могут поступать модули, поэтому есть "подклассы" этого Абстрактного модуля . Тот, о котором мы здесь говорим, называется Исходный текстовый модуль .
Source Text Module : Abstract Module {
ECMAScriptCode // Concrete syntax tree of actual source text
RequestedModules // List of imports parsed from source text
LocalExportEntries // List of exports parsed from source text
Evaluate() // interprets ECMAScriptCode
}
Когда переменная объявляется в модуле (const a = 5
), она сохраняется в Environment
модуля. Если добавить к этому объявление export
, оно также будет отображаться в LocalExportEntries.
Когда вы import
модуль, вы фактически захватываете объект Namespace
, который имеет экзотическое поведение, что означает, что, хотя он кажется нормальным объектом, такие вещи, как получение и установка свойств, могут делать разные вещи, чем вы ожидали.
В случае Объекты пространства имен модуля , получив свойство namespace.a
, фактически ищет это свойство как имя в ассоциированном Environment
.
Итак, если у меня есть два модуля, A и B:
// A
export const a = 5;
// B
import { a } from 'A';
console.log(a);
Модуль B импортирует A, а затем в модуле B a
связывается с A.Namespace.a
. Поэтому, когда к модулю b
осуществляется доступ к a
, он на самом деле ищет его в A.Namespace
, а в A.Environment
. (Вот как на самом деле работают живые привязки).
Наконец, на тему карты вашего модуля. Все модули будут созданы до того, как их можно будет оценить. Instantiation - это процесс разрешения графа модуля и подготовки модуля для оценки.
Модуль Карта
Идея «карты модулей» зависит от конкретной реализации, но для браузеров и узлов она выглядит следующим образом: Module Map <URL, Abstract Module>
.
Хороший способ показать, как браузеры / узлы используют этот модуль, карта динамическая import()
:
async function import(specifier) {
const referrer = GetActiveScriptOrModule().specifier;
const url = new URL(specifier, referrer);
if (moduleMap.has(url)) {
return moduleMap.get(url).Namespace;
}
const module = await FetchModuleSomehow(url);
moduleMap.set(url, module);
return module.Namespace;
}
Вы можете увидеть это точное поведение в Node.js: https://github.com/nodejs/node/blob/e24fc95398e89759b132d07352b55941e7fb8474/lib/internal/modules/esm/loader.js#L98