Значения импорта, отключенные от их значений экспорта, по-прежнему доступны только для чтения?

Дана следующая структура модуля:

// module A:
export let a = 1; // named export
export function inc() { a++; } // named export

// module B:
let b = 1;
export default b; // default export (equivalent to `export default 1`)
export function inc() { b++; } // named export

// module C:
let c = {};
export default c; // default export

// module E:
import a, {inc as incA} from "./A";
import b, {inc as incB} from "./B";
import c from "./C";

incA();
console.log(a); // logs 2, because "a" has a live connection to the export value
a++; // Error (because a is a live read-only view on the export)

incB();
console.log(b); // logs 1, because "b" is disconnected from the export value
b++; // Does this throw an error as well?

c.prop = true; // I think mutations are always allowed, right?
c = {}; // but are reassignment allowed too?

Если у меня есть экспорт выражения по умолчанию (export default b или export default 1), соответствующий импорт отключается от этого значения экспорта. Учитывая это, такой импорт все еще доступен только для чтения, то есть я могу переназначить a или c?


person Community    schedule 02.09.2016    source источник
comment
Разве вы не можете просто запустить код и посмотреть результаты?   -  person jcubic    schedule 02.09.2016
comment
Вы можете попробовать запустить код с помощью node --harmony   -  person jcubic    schedule 02.09.2016


Ответы (1)


Привязки импорта всегда доступны только для чтения, см. аннотацию CreateImportBinding операция в спецификации, шаг 5:

  1. Создайте неизменяемую косвенную привязку в envRec для N, которая ссылается на M и N2 как его целевая привязка и запись о том, что привязка инициализирована.

(выделено мной)

Эта операция используется ModuleDeclarationInstantiation при обработке импортные записи модуля.

So:

b++; // Does this throw an error as well?

Да, b доступен только для чтения.

c.prop = true; // I think mutations are always allowed, right?

Если экспортируемый объект это позволяет, то да.

c = {}; // but are reassignment allowed too?

Нет, c доступен только для чтения.


В комментарии вы сказали:

но когда живого связывания уже нет, нет смысла делать такие переменные только для чтения

Полезно помнить, что это не переменные, а привязки. Хотя переменные — это один из видов привязки, не все привязки являются переменными (даже в ES5 и более ранних версиях).

Что касается того, что они доступны только для чтения, когда это не имеет значения, помните, что задействованы два уровня привязок:

  1. Активная привязка export в исходном модуле.
  2. Активная привязка import в потребляющем модуле.

Чтобы сделать № 2 доступным для записи, когда значение из № 1 не изменится, механизм импорта должен знать это, но эта информация не находится в экспорт модуля. Экспорт просто дает имя экспортируемой привязки.

Более того, наличие изменяемых привязок импорта, а также неизменяемых привязок импорта сложнее для понимания и сложнее в реализации. (Переназначение импортированных привязок также сбивает с толку с точки зрения стиля.)

Также важно помнить, что тот факт, что они являются активными привязками, означает, что значение импорта может измениться. Предполагать:

mod1.js:

export let foo = 41;
export function incrementFoo() {
    ++foo;
};

mod2.js:

import { foo, incrementFoo } from "./mod1.js";
console.log(foo); // 41
incrementFoo();
console.log(foo); // 42 <== it changed

В этом конкретном случае это был код в mod2.js, который вызвал изменение (путем вызова incrementFoo), но это не обязательно. Это может быть связано с тем, что в mod1.js произошло какое-то событие, связанное со временем, которое привело к изменению значения, или в результате вызова какого-либо другого модуля в mod1.js и т. д.

Но поскольку foo mod2.js является живой привязкой к foo mod1.js, mod2.js видит изменение.

person T.J. Crowder    schedule 02.09.2016
comment
Хм, но когда live-binding уже нет, нет смысла делать такие переменные только для чтения. - person ; 02.09.2016
comment
@LUH3417: это не переменные, это привязки. (Переменные — это один вид привязки, но не все привязки являются переменными.) Я не могу сказать, почему комитет решил сделать все привязки импорта неизменяемыми, но это определенно проще (проще понять, проще реализовать), а также раскрывает меньше внутренностей модуля. Если вам нужна переменная, просто создайте ее let b2 = b; b2++; - person T.J. Crowder; 02.09.2016
comment
Вы правы, я просто пытаюсь глубже понять концепцию. Спасибо! - person ; 02.09.2016
comment
Я более внимательно изучил тему. Мы действительно говорим об экспортируемых привязках имен, а не о переменных. Привязка заданного имени может измениться только тогда, когда его лексический идентификатор изменяется динамически (что невозможно), его лексическая область видимости изменяется динамически (что также невозможно) или имеет место рекурсия. С этой точки зрения вполне логично, что импорт экспортированных привязок имен всегда доступен только для чтения. - person ; 03.09.2016
comment
Вот связанный ответ - person ; 03.09.2016