导入值与其导出值断开连接是否仍然是只读的?
Are import values disconnected from their export values still read-only?
给出的是以下模块结构:
// 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
吗?
导入绑定始终是只读的,请参阅规范中的抽象 CreateImportBinding
操作,第 5 步:
- Create an immutable indirect binding in envRec for N that references M and N2 as its target binding and record that the binding is initialized.
(我的重点)
ModuleDeclarationInstantiation
在处理模块的导入条目时使用该操作。
所以:
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
是只读的。
在评论中,您说:
but when there isn't a live-binding anymore, it makes no sense to make such variables read-only
记住它们不是变量,它们是绑定,这很有用。虽然变量是一种绑定,但并非所有绑定都是变量(即使在 ES5 和更早版本中)。
关于它们在无关紧要时是只读的,请记住涉及两层绑定:
- 源模块中 export 的实时绑定。
- 消费模块中导入的实时绑定。
为了在#1 的值不会改变时使#2 可写,导入机制必须知道这一点,但该信息不在 the module's exports 中。导出仅给出导出绑定的名称。
此外,具有可变导入绑定和不可变导入绑定更难理解,更难以实现。 (从样式的角度来看,重新分配导入的绑定也是令人困惑的。)
记住它们是实时绑定这一事实也很重要,这意味着导入的值可能会改变。假设:
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
的结果,等等
但是因为 mod2.js
的 foo
是 mod1.js
的 foo
的实时绑定,所以 mod2.js
看到了变化。
给出的是以下模块结构:
// 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
吗?
导入绑定始终是只读的,请参阅规范中的抽象 CreateImportBinding
操作,第 5 步:
- Create an immutable indirect binding in envRec for N that references M and N2 as its target binding and record that the binding is initialized.
(我的重点)
ModuleDeclarationInstantiation
在处理模块的导入条目时使用该操作。
所以:
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
是只读的。
在评论中,您说:
but when there isn't a live-binding anymore, it makes no sense to make such variables read-only
记住它们不是变量,它们是绑定,这很有用。虽然变量是一种绑定,但并非所有绑定都是变量(即使在 ES5 和更早版本中)。
关于它们在无关紧要时是只读的,请记住涉及两层绑定:
- 源模块中 export 的实时绑定。
- 消费模块中导入的实时绑定。
为了在#1 的值不会改变时使#2 可写,导入机制必须知道这一点,但该信息不在 the module's exports 中。导出仅给出导出绑定的名称。
此外,具有可变导入绑定和不可变导入绑定更难理解,更难以实现。 (从样式的角度来看,重新分配导入的绑定也是令人困惑的。)
记住它们是实时绑定这一事实也很重要,这意味着导入的值可能会改变。假设:
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
的结果,等等
但是因为 mod2.js
的 foo
是 mod1.js
的 foo
的实时绑定,所以 mod2.js
看到了变化。