构造函数在prototype上挂载常量,本质是让所有实例共享不可变的原始值(如字符串、数字、布尔值),以节省内存并保证一致性;引用类型需用Object.freeze()冻结或getter隔离,避免共享副作用。

构造函数在 prototype 上挂载常量,本质是把不随实例变化的、通用的只读值(如类型标识、默认配置、状态码等)定义在原型对象上,让所有实例通过原型链共享同一份内存引用。关键在于区分“值类型常量”和“引用类型陷阱”,避免意外共享可变数据。
推荐方式:挂载原始值(string/number/boolean)
原始值(primitive)是不可变的,挂到 prototype 上安全、高效,所有实例读取的是同一个字面量值:
- 直接赋值即可:无需特殊封装,也不涉及内存别名问题
- 适合场景:枚举值、固定标签、版本号、默认开关状态等
示例:
function User(name) { this.name = name; }User.prototype.ROLE_ADMIN = 'admin';
User.prototype.MAX_LOGIN_ATTEMPTS = 5;
User.prototype.IS_ACTIVE = true;
const u1 = new User('Alice');
const u2 = new User('Bob');
console.log(u1.ROLE_ADMIN === u2.ROLE_ADMIN); // true
console.log(u1.MAX_LOGIN_ATTEMPTS === 5); // true
慎用方式:挂载对象或数组类常量
引用类型(Object、Array、Function 等)一旦挂到 prototype,所有实例将共享同一份内存地址——这在作为“常量”使用时极易引发副作用:
立即学习“Java免费学习笔记(深入)”;
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
-
❌ 错误示范:
User.prototype.permissions = ['read'];→ 修改u1.permissions.push('write')会同步影响u2.permissions -
✅ 安全替代:用
Object.freeze()冻结对象,或改用 getter 返回新副本
安全写法示例:
// 冻结后不可增删改,真正成为“只读常量”User.prototype.DEFAULT_CONFIG = Object.freeze({
theme: 'light',
lang: 'zh-CN'
});
// 或用 getter 每次返回新对象(适合需隔离的轻量结构)
User.prototype.getEmptyCart = function() {
return { items: [], total: 0 };
};
为什么不能直接在构造函数里初始化 prototype 常量?
prototype 是一个普通对象,可以随时赋值属性。但要注意两点:
- 顺序无关:可在构造函数声明前、后、甚至运行时动态添加,只要在实例创建前或后访问都有效
-
避免覆盖整个 prototype:不要写
User.prototype = { ROLE_ADMIN: 'admin' }—— 这会切断原有 constructor 指向,并丢失已有的方法(如之前定义的sayName)
正确做法是逐个添加,或用 Object.assign(User.prototype, { ... }) 合并。
验证常量是否真正共享
可通过以下方式确认挂载成功且行为符合预期:
- 检查
实例.constructor.prototype.常量名是否存在 - 比对两个不同实例访问该常量的引用是否相等(原始值恒为
true;冻结对象也应为true) - 尝试修改(如对数组
push),观察是否波及其他实例(若发生,说明未冻结或误用了引用类型)

















