核心是用 Object.freeze() 冻结原型并设 prototype 属性为不可配置,再用 defineProperty 定义不可写不可配置方法,或改用实例方法规避篡改风险。

避免直接修改类原型,核心是“锁住它”——不是靠约定或文档提醒,而是用 JavaScript 提供的底层控制能力,让修改在运行时失败或静默无效。
冻结原型对象本身
最直接有效的方式是调用 Object.freeze() 锁定整个原型对象:
- 执行
Object.freeze(MyClass.prototype)后,无法新增、删除或重写原型上的任何自有属性(包括方法) - 该操作会递归冻结所有已存在的数据属性(但不会冻结嵌套对象,如需深度冻结需额外处理)
- 建议在类定义完成、首次实例化前立即执行,防止后续模块意外篡改
禁用 prototype 属性的可配置性
仅冻结原型还不够——攻击者可能直接替换整个 MyClass.prototype:
- 用
Object.defineProperty(MyClass, 'prototype', { configurable: false })封死构造函数的 prototype 属性 - 此后再执行
MyClass.prototype = {...}将静默失败(非严格模式)或抛错(严格模式) - 这一步和冻结原型配合,构成双重防护
用 defineProperty 替代直接赋值
如果必须在原型上添加方法或常量,别用 MyClass.prototype.method = ... 这种裸赋值:
立即学习“Java免费学习笔记(深入)”;
- 它生成的属性默认
writable: true、configurable: true,极易被覆盖 - 改用
Object.defineProperty(MyClass.prototype, 'method', { value() {}, writable: false, configurable: false }) - 这样定义的方法既不可重写,也不可删除,语义更接近“只读接口”
优先使用实例方法而非原型方法
对关键逻辑或易被覆盖的行为,考虑不挂到原型上:
- 在 constructor 中定义
this.handleClick = () => { ... },绑定到实例自身 - 虽然每个实例多占一点内存,但完全规避了原型级篡改风险
- 适合生命周期短、行为强隔离的场景(如事件处理器、回调钩子)


















