const声明必须初始化,否则编译报错;C/C++、Java、TypeScript、C#均强制要求编译期确定值,因常量需参与优化与校验;TS的const仅类型检查有效,运行时可篡改。
const 声明必须初始化,否则编译直接报错
几乎所有主流语言(c/c++、java、typescript、c#)都要求 const 或等效修饰符(如 final)声明的常量在定义时就赋予确定值。这不是建议,是硬性语法限制——没初始化,代码根本过不了编译。
- C/C++:
const int MAX_SIZE;→ 编译错误:“uninitialized const variable” - TypeScript:
const API_TIMEOUT;→ TS2451:“Cannot initialize a const declaration with an undefined value” - Java:
static final String DB_URL;(类级别)→ 必须在声明处或静态块中赋值,否则编译失败
原因很简单:常量本质是编译期确定的不可变值,编译器需要它来做优化、校验、内存布局。运行时才决定值?那就不叫常量,叫“只读变量”了。
const 指针和指向 const 的指针,搞混就改不了数据也移不动地址
C/C++ 里 const 位置不同,语义天差地别。新手常以为加了 const 就“全锁死”,结果要么误改了内容,要么死活没法把指针指向新地址。
-
char* const ptr = &a;→ 指针本身是常量(地址不能变),但*ptr可改 -
const char* ptr = &a;→ 指向的内容是常量(*ptr不能改),但指针可重新赋值 -
const char* const ptr = &a;→ 地址和内容双锁定,最严格
典型坑:想传一个“只读字符串”给函数,却写了 void func(char* const s),实际调用时仍可能被函数内部修改内容;正确写法应是 void func(const char* s)。
Java 和 C# 里 static final / const 是编译时常量,但有隐含前提
Java 的 static final 和 C# 的 const 确实会在编译期内联展开(比如 MAX_SIZE 出现 10 次,字节码里就是 10 个数字),但前提是它的初始值必须是编译期常量表达式。
- ✅ 合法:
static final int PORT = 8080;,const double PI = 3.14159; - ❌ 非法(Java):
static final long NOW = System.currentTimeMillis();→ 编译不过,因为不是编译期可算的值 - ⚠️ 注意(C#):
const只支持基本类型和字符串;static readonly才能放对象实例(如new List<int>())
这个区别直接影响序列化、反射行为和跨程序集引用——如果依赖方没重编译,而你改了 const 值,它还用着旧的内联值。
TypeScript 的 const 不是编译期常量,只是语法层只读约束
TypeScript 的 const 只在类型检查阶段起作用,编译后生成的 JavaScript 仍是 var 或 let(取决于 target),运行时完全不阻止重赋值。
- TS 写:
const API_BASE = "https://api.example.com"; - 编译后 JS 可能是:
var API_BASE = "https://api.example.com"; - 运行时执行
API_BASE = "http://hacked.com";→ 完全不会报错(除非启用了严格模式 +Object.freeze手动加固)
所以 TypeScript 的 const 主要防手误和提供类型推导,别指望它挡住运行时篡改。真要保障不可变,得靠运行时手段(如 Object.freeze)或构建时注入(如 Webpack DefinePlugin)。
最容易被忽略的是:跨文件常量引用、环境变量注入、JSON 配置加载这些场景下,“声明即常量”的假象特别强,但实际值可能来自运行时解析——这时候用 const 只是图个心安,该变还是变。










