ESModule具名导出是实时引用而非值拷贝,支持源模块修改后所有导入方同步更新;const导出对象属性可变,但不可重赋值;推荐用对象封装逻辑关联变量以增强语义一致性。

ESModule 中使用 export 具名导出多个变量时,它们本身并不自动构成“强绑定关系”——JavaScript 的具名导出本质是**按名称绑定的实时引用(live binding)**,而非值拷贝。所谓“强绑定”,实际指的是模块系统保证:导出的变量在源模块中被修改后,所有导入该变量的模块都能看到最新值(前提是变量可变,如对象、数组;若导出的是原始值如字符串、数字,则无法在外部修改其值,但重新赋值仍会触发更新)。
具名导出多个变量:语法与基本写法
你可以用多个独立的 export 语句,也可以用一个 export 后跟大括号批量导出:
-
方式一(分散导出):
export const a = 1;<br>export let b = 'hello';<br>export const obj = { x: 0 }; -
方式二(批量导出):
const a = 1;<br>let b = 'hello';<br>const obj = { x: 0 };<br>export { a, b, obj };
两种方式语义等价,都建立名称到声明变量的**实时绑定**(live binding)。
理解“强绑定”的关键:实时引用而非快照
ESM 的具名导出不是导出那一刻的值副本,而是对原始声明位置的**只读绑定(read-only binding)**。这意味着:
立即学习“Java免费学习笔记(深入)”;
- 如果导出的是
let或var声明的变量(非const),源模块修改它,所有导入处都会反映变化; - 如果导出的是
const obj = {...},虽然obj本身不可重新赋值,但它的属性可变(obj.x = 2),导入方能立刻看到; - 导入方不能通过
import { a } from './mod.js'然后a = 5来修改它(会报错),因为绑定是只读的; - 但源模块内部执行
a = 5(前提是a是let或var),所有导入a的地方都会同步更新。
保持逻辑关联:用对象或命名空间封装
若你希望多个变量天然保持“一组”的语义(比如配置项、状态集合),推荐将它们组织在一个对象中导出,再配合解构或命名空间导入:
- 导出:
export const config = {<br> timeout: 5000,<br> baseUrl: 'https://api.example.com',<br> retry: true<br>}; - 导入并响应变更:
import { config } from './config.js';<br>// 修改 config 属性(合法)<br>config.timeout = 10000;<br>// 所有导入 config 的模块立即感知到 timeout 变为 10000
这种方式比导出一堆独立变量更利于维护“强逻辑绑定”,也避免了因分散导出导致的更新不同步风险。
注意:避免意外断开绑定的常见错误
以下写法会**破坏实时绑定**,变成静态值拷贝:
-
const a = 1; export { a as A };✅ 正确(仍是绑定) -
export default { a: 1, b: 2 };❌ 默认导出是值,不是绑定(对象内容可变,但整个 default 导出不能被源模块重赋值) -
const obj = {}; export { obj }; obj.x = 1;✅ 绑定有效(obj引用不变,属性改了) -
let obj = {}; export { obj }; obj = { y: 2 };✅ 导入方会看到obj变成新对象(因为obj是let,重赋值触发绑定更新) -
const obj = {}; export { obj }; obj = { y: 2 };❌ 报错(const不允许重赋值)
只要不重新声明导出变量(如用 var 重复声明)、不覆盖导出绑定本身,ESM 就能维持预期的响应式行为。


















