应将引用类型属性在构造函数或类字段中初始化以确保实例独立,避免原型链污染;需过滤敏感键并冻结原生原型增强防护。

原型链属性共享本身不是问题,问题出在引用类型属性被多个实例共用,导致修改一个就影响全部。关键不是“避免共享”,而是让每个实例拥有独立副本,同时防止外部输入意外写入原型。
构造函数里初始化引用属性
这是最稳妥、兼容性最好的方式。每次 new 都会执行构造函数,天然隔离数据。
- 把数组、对象、Map 等引用类型声明在构造函数内部,而不是挂到 prototype 上
- 子类继承时,必须在子构造函数中调用 Parent.call(this),确保父类的初始化逻辑运行在当前实例上
- 示例:function User() { this.permissions = []; this.settings = {}; } —— 每个实例都有自己的 permissions 数组
用类字段语法(推荐 ES6+)
语义清晰,自动绑定到实例,无需手动 call,也避开 prototype 污染风险。
- 写成 class Profile { roles = []; config = { theme: 'light' }; 即可
- 它等价于在构造函数中赋值,但更简洁、可读性更强
- 注意别写成 static roles = [],那是真正的共享,所有实例共用一个数组
过滤敏感键,防原型链污染
很多“污染”其实来自外部输入误写入 __proto__ 或 constructor,不是代码设计问题,而是数据处理疏忽。
立即学习“Java免费学习笔记(深入)”;
- 解析 JSON 后不要直接 Object.assign(target, data),先校验 key 是否在白名单里
- 手动递归合并或使用 lodash.merge 时,务必过滤掉 __proto__、constructor、prototype 及其大小写变体
- 现代环境优先用 structuredClone() 做深拷贝,它天然跳过原型相关键
冻结原生原型,加一层硬防护
在应用启动最早期(比如第一个 script 标签顶部)冻结关键原型,堵住最底层入口。
- 执行 Object.freeze(Object.prototype)、Object.freeze(Array.prototype) 等
- 严格模式下,尝试污染会立即报错;非严格模式下静默失败,同样能阻断攻击
- 搭配 Object.create(null) 创建配置对象,彻底切断原型链,免疫污染


















