const
和 let
的唯一区别在于,const
声明的变量不能被重新赋值(只读变量)。例如,下面的代码会报错:
注:本文不会使用“常量”这个术语,因为它容易产生歧义。例如:
- 有些人将数字、字符串等不可改变的字面量称为常量。
- 有些人把一些只读属性(如
Math.PI
)称为常量。- 还有人把 ES6 中
const
声明的变量称为常量。
但一般来说,这些歧义并不会影响理解。
const
赋值错误:静态错误 vs 运行时错误
遗憾的是,为 const
变量重新赋值并不是静态错误(static error),而是运行时错误(runtime error)。
- 静态错误(static error):解析时就能检测到的错误,规范中称为提前错误(early error)。
- 运行时错误(runtime error):代码执行过程中才会抛出的错误。
为什么静态错误更好?
通常来说,错误越早发现越好。例如:
如果 foo = 2
是静态错误,开发环境就能直接报错,即使这行代码没有被执行到。
const
赋值为何不是静态错误?
早期 const
设计:静态 + 运行时错误
在 2011 年 const
刚进入 ES6 草案时,严格模式下为 const
变量重新赋值会抛出 静态错误(SyntaxError),同时在运行时也会抛出 运行时错误(TypeError)。Firefox 7 的 SpiderMonkey 也实现了这一规则。
后来,在 2012 年,草案修改为不论是否严格模式,都抛出静态错误。Firefox 36 在 2014 年 11 月 19 日实现了这一改动。
为什么 const
不能完全是静态错误?
有些情况很难静态检测,比如:
1. eval()
动态执行代码
引擎无法在解析阶段静态检测 eval()
里的 foo = 2
。
2. 变量声明顺序影响静态检测
在解析 foo = 2
时,foo
还未声明,引擎无法静态检测错误。
3. const
变量分散在多个 <script>
标签中
解析第二个 <script>
时,引擎可能不会去检查 foo
是否在前面声明过。
TC39 最终决策:移除 const
赋值的静态错误
在 2014 年 11 月 18 日的 TC39 会议上,委员会决定:
- 删除
const
变量赋值的静态错误,只留下运行时错误。 - 原因:
- 不同引擎对“哪些情况要报静态错误”达不成共识。
- V8 认为静态检测
const
赋值错误会导致性能问题,且难以优化。 - 这种错误较少见,可以交给 ESLint 这样的工具来检测。
Firefox 的 SpiderMonkey 实现了静态错误后,被 TC39 要求撤回,开发者对此也表示不满。
const
在代码风格中的使用
目前推荐的代码风格是:
- 默认使用
const
,只有当变量需要重新赋值时才使用let
。 - ESLint 提供
prefer-const
规则来强制执行这种风格。 - 但如果没有
no-const-assign
规则配合,可能会导致const
变量被误修改而在生产环境抛出TypeError
。
如何判断错误是静态错误还是运行时错误?
一般情况下:
- SyntaxError 通常是静态错误。
- 其他类型的错误通常是运行时错误。

结论
const
变量不能重新赋值,但这不是静态错误,而是运行时错误。- 早期 ES6 版本尝试将
const
赋值错误作为静态错误,但最终放弃。 - 运行时错误仍然保留,并且不受严格模式影响。
- 代码风格推荐:默认使用
const
,只有在需要修改变量时才用let
。 - 使用 ESLint
prefer-const
规则,同时配合no-const-assign
,避免潜在 bug。 - 静态错误和运行时错误的区别可通过
alert()
进行简单测试。
这就是 const
赋值错误背后的故事,它不仅仅是个语法设计问题,更涉及到编译器实现、性能权衡和语言规范的演变。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
本文暂时没有评论,来添加一个吧(●'◡'●)