ES6 назвал импорт вводит const?

При реализации механизма модулей Python поверх модулей ES6 для компилятора Transcrypt Python to JavaScript я столкнулся со следующей проблемой:

Существует большое количество стандартных функций, импортированных из модуля времени выполнения Python, например, Python. input функция (реализована в JS), которая может быть сделана доступной с помощью именованного импорта (так как им не нужно добавлять префикс к чему-либо в коде пользователя, поэтому input скорее, чем __runtime__.input, чтобы соответствовать Python).

В Python разрешено повторное связывание именованного импорта. Поэтому я определяю другую функцию input, который переопределит тот из среды выполнения. Но если я делаю это в JS, я получаю ошибку:

Идентификатор input уже объявлен

Кажется, что все импортированные имена рассматриваются как JS-константы, поэтому не подлежат повторному связыванию в соответствии с этой статьей. Я могу придумать несколько хитрых обходных путей, таких как импорт под псевдонимом и последующее присвоение модулю глобального var, а не const, но мне нравится, чтобы все было просто, поэтому мой вопрос:

  • Прав ли я, что именованные импорты JS являются консистентными, поэтому не подлежат повторному связыванию (и если да, то просто любопытно, кто-нибудь знает ПОЧЕМУ)? Где я могу найти подробности об этом?
  • Есть ли простой способ обойти это и все же поместить их в глобальное пространство имен импортирующего модуля, но переопределить их по желанию?

1 ответ

В соответствии со спецификацией языка импортированные привязки являются неизменными, поэтому их нельзя изменить. Идентификаторы зарезервированы, когда модуль анализируется из-за того, как работают модули ES6: в отличие от Python, импорт не является оператором, который включается по мере выполнения; вместо этого все импорты модуля в основном собираются во время ранней компиляции и затем разрешаются до того, как модуль начинает выполняться.

Это делает модули ES6 непригодными в качестве реализации для системы импорта Python.

Как правило, чтобы не потерять эти имена, вы можете просто присвоить импортированным привязкам разные имена. Например, from foo import bar, baz может быть скомпилировано в следующее:

import { bar as _foo__bar, baz as _foo__baz } from 'foo';
let bar = _foo__bar;
let baz = _foo__baz;

Это зарезервирует только некоторые специальные имена, сохраняя при этом bar а также baz идентификаторы изменяемые.

Другой способ, который, вероятно, также поможет вам решить возможные различия в семантике импорта, заключается в простом создании замыкания:

import { bar, baz } from 'foo';

(function (bar, baz) {
    // …

})(bar, baz);

Или даже добавить какой-то другой механизм поиска между ними.


Btw. Питона import очень похож на Node's requireтак что, возможно, стоит рассмотреть все те решения, которые позволили модульной системе Node работать в браузере.

Другие вопросы по тегам