Модули ES6: импортированные константы undefined сначала; они становятся доступными позже
Я использую модули ES6 в своем приложении JavaScript. Источники скомпилированы с помощью webpack и babel. Это сокращенная версия файла, которая вызывает у меня проблемы:
export const JUST_FORM = 0;
export const AS_PAGE = 1;
console.log(AS_PAGE); // **
export default function doSomething(mode = AS_PAGE) {
console.log(mode);
console.log(JUST_FORM);
}
Я использую эту функциональность так же, как вы ожидали.
import doSomething, { AS_PAGE } from './doSomething'
console.log(AS_PAGE);
doSomething();
Когда я запускаю приложение, он печатает три раза undefined
и только после ожидаемого значения AS_PAGE
, которое является console.log
, помеченным **
. Однако это напечатано последним! Он показывает, что:
- Константа
AS_PAGE
, когда используется как параметр по умолчанию для функции doSomething
, не определяется в момент определения функции.
- Константа
JUST_FORM
не определяется при вызове doSomething
.
- Константа
AS_PAGE
не определена при явном импорте.
По-видимому, здесь происходит то, что только экспорт default
обрабатывается и оценивается, а остальная часть файла игнорируется до следующего. Я импортирую этот файл в несколько разных мест в моем приложении (который в настоящий момент довольно велик), и в какой-то момент эти значения становятся фактически доступными. Судя по выводам консоли, это вопрос времени, но вполне возможно, что у него есть другая причина. Очевидно, что я импортирую точно так же во всех местах.
В любом случае, я написал все свое приложение с предположением, что как только я что-то импортирую, он сразу же доступен, и я могу использовать его в своем коде. Я прочитал (кратко) о том, как модули ES6 должны работать, и я не нашел ничего, что могло бы доказать, что это предположение неверно. И он работает до сих пор.
Также обратите внимание, что поведение такое же, когда я запускаю его с помощью webpack-dev-server
или скомпилировал его в один пакет.
Действительно ли это поведение? Что может быть причиной этого?
Ответы
Ответ 1
Как указано в комментариях, здесь мы получаем круговые зависимости.
В коде, представленном в вопросе, фактически нет круговой зависимости (потому что это просто упрощенный фрагмент кода), но симптомы очень ясны.
Простейшим примером циклической зависимости является то, что файл A импортирует файл B, а файл B импортирует A. К сожалению, иногда это затрудняет определение того, что круг может быть сколь угодно большим, охватывая огромное количество файлов.
Циркулярные зависимости поддерживаются в ES6, и их можно использовать, когда вы достаточно осторожны. Тем не менее, мой взнос здесь заключается в том, что круговые зависимости часто являются признаком плохих проектных решений. Это был именно мой случай.