ES模块import导入的let变量为何赋值触发常量错误?
报错核心原因
ES Module 规范中,import 导入的模块绑定默认是只读的常量引用,这个只读特性和原模块中声明变量时用let还是const没有任何关系:
- 你在
users.js里用let声明的users变量,可变权限仅局限在users.js这个模块的内部作用域,模块内部自己给users重新赋值完全合法。 - 当你通过
export default导出这个变量时,不会把变量的“可变权限”一起导出,只会给导入方创建一个指向原变量的实时只读绑定。这种绑定是同步的:原模块内部如果修改了users的指向,导入侧拿到的users值也会同步更新,但导入方自身没有权限重新给这个绑定赋值。导入方拿到的users标识符,在自身模块作用域里的效果和const声明完全一致,直接对其重新赋值就会触发Assignment to constant variable的类型错误。
注意:这个只读限制只针对「重新给导入的标识符赋值」的行为,如果你修改的是标识符指向的引用类型值本身的内容,是完全允许的,比如执行
users.push('Tom')、users.length = 0这类操作不会有任何报错,因为你没有改变绑定的指向,只是修改了绑定指向的数组内容。
逻辑拆解
我们可以把你写的三段代码的执行逻辑拆成三步看:
package.json里配置"type": "module"只是告诉Node.js把当前项目下的.js文件按ES Module规范解析,和报错本身没有直接关联。users.js中let users = ["Jack", "Mary"]声明的是模块内部变量,export default users导出的是对这个变量值的只读引用,不是变量本身、也不是值的静态拷贝。index.js中import users from './users.js'拿到的是只读绑定,执行users = []是试图在当前模块作用域修改这个只读绑定的指向,直接触发常量赋值错误。
可行的修复方案
根据你的实际需求选对应的方案即可:
- 如果只是想操作数组内容(比如清空、新增元素),不要重新赋值绑定,直接操作数组本身:
import users from './users.js'; // 清空原数组,不改变绑定指向 users.length = 0; // 新增元素 users.push('Bob');
- 如果确实需要在外部重新给原模块的
users变量赋值,不要直接在导入侧改绑定,在定义变量的模块里暴露修改方法,通过方法触发内部的赋值操作:
修改users.js:
let users = ["Jack", "Mary"]; // 暴露修改内部变量的方法 export function setUsers(newUsers) { users = newUsers; } export default users;
在index.js中调用方法修改:
import users, { setUsers } from './users.js'; // 调用原模块暴露的方法修改内部变量,合法 setUsers([]);
内容的提问来源于stack exchange,提问作者devope
相关产品推荐
相关产品推荐

