#typescript #ecmascript-6
Вопрос:
Я пытаюсь понять разницу между import
и require
когда дело доходит до экспорта / импорта изменяемых значений.
Представьте себе файл a.ts:
export let a = 1;
export function f() {
a = 2;
}
Затем три версии основного файла, index1.ts:
import { a, f } from "./a";
console.log(a); // 1
f();
console.log(a); // 2
индекс 2.ts:
const { a, f } = require("./a");
console.log(a); // 1
f();
console.log(a); // 1
индекс 3.ts:
const _ = require("./a");
console.log(_.a); // 1
_.f();
console.log(_.a); // 2
- Я ожидал, что index1.ts выдаст тот же результат, что и index2.ts, но это не так.
import
eda
всегда ссылается на фактическуюa
переменную из. ts. Каковы гарантии того, что так будет всегда ? Является ли спецификация причиной такого поведения ? - index3.ts работает, потому что свойства возвращаемого объекта
require
являются получателями. Опять же, гарантировано ли, что это всегда будет правдой ? Можем ли мы положиться на это, например, при проектировании библиотеки ?
Комментарии:
1.
import
создает псевдоним, а не новую переменную.const
создает переменную, которая принимает копию значения.
Ответ №1:
Идентификаторы, импортированные с import
помощью, могут вести себя странно — они, по-видимому, могут переназначить себя самостоятельно, если модуль, который их экспортирует, переназначает экспортируемое, вот почему
import { a, f } from './a';
console.log(a);
f()
console.log(a);
действительно, может войти 1, а затем 2 — чего вы не увидите ни в каком другом JavaScript.
Является ли спецификация причиной такого поведения ?
Да, это так.
Использование require
вместо import
, с другой стороны, возвращает объект пространства имен, экспортированный другим модулем, вместо создания переменных модуля со странным поведением. Этот объект работает так, как вы ожидали бы от любого другого объекта в Javascript — если вы деструктурируете значения объекта в переменные, эти значения не «изменятся сами по себе», если вы явно не сделаете что-то подобное a = someOtherValue
в текущей области.
index3.ts работает, потому что свойства объекта, возвращаемого require, являются получателями. Опять же, гарантировано ли, что это всегда будет правдой ? Можем ли мы положиться на это, например, при проектировании библиотеки ?
Это немного больше похоже на то, что значения свойств объекта пространства имен переназначаются, когда модуль, из которого они экспортируются, переназначает их. Если у вас есть
// foo.ts
export let a = 1;
export function f() {
a = 2;
}
тогда объект пространства имен, импортированный в другое место, будет живой структурой, содержащей
{
a: currentValueOfAInFoo,
f: currentValueOfFInFoo,
}
Тем не менее, хотя от этого поведения можно зависеть, я бы настоятельно рекомендовал никогда не писать код, который полагается на него, потому что это довольно странно по сравнению с тем, как обычно следует ожидать поведения идентификатора — это потенциально сбивает с толку читателей кода и авторов кода, которые должны учитывать.