防止原型链被扩展本质是锁定对象[[prototype]]内部槽位,可通过object.preventextensions()、seal()或freeze()实现;冻结原生原型如object.prototype可防全局污染;用object.create(null)创建无原型对象可彻底规避继承链风险。

防止对象原型链被扩展,本质是阻止该对象的 [[Prototype]] 内部槽位被修改——即不让它切换到另一个原型。这和“禁止对象自身扩展”(Object.preventExtensions)不同,关键在于对象是否“可扩展”:一旦对象不可扩展,Object.setPrototypeOf() 和隐式 __proto__ 赋值就会失败。
让对象不可扩展即可锁定原型链
JavaScript 规范明确规定:只有可扩展的对象才允许修改其原型。因此最直接有效的方式,就是调用 Object.preventExtensions() 或更严格的冻结方法:
-
Object.preventExtensions(obj):仅禁止新增属性,但同时锁死[[Prototype]],后续Object.setPrototypeOf(obj, newProto)在严格模式下抛TypeError,非严格模式静默失败 -
Object.seal(obj)或Object.freeze(obj):它们都基于preventExtensions,所以同样能阻断原型变更,且额外限制属性操作
冻结原生原型防止全局污染
若目标是防止整个环境的原型链被篡改(比如有人给 Object.prototype 加方法),需在应用最早期冻结原生构造器的原型:
- 在
中第一个<script></script>里执行:Object.freeze(Object.prototype);<br>Object.freeze(Array.prototype);<br>Object.freeze(String.prototype);
- 冻结后,任何尝试向这些原型添加属性(如
Array.prototype.last = function(){...})都会失败——严格模式报错,非严格模式忽略 - 注意:必须早于所有业务代码和第三方 SDK 执行,否则可能已被污染
用无原型对象彻底规避继承链
对纯数据容器(如配置、映射表、临时合并结果),根本不需要原型链。此时应主动创建无原型对象:
- 用
Object.create(null)替代{},它没有__proto__、不继承toString或hasOwnProperty - 判断属性存在时,改用
Object.prototype.hasOwnProperty.call(obj, key),避免依赖对象自身的hasOwnProperty - 这种对象天然免疫
__proto__注入类原型污染,结构确定、行为可控
配合静态检查与工程约束
单靠运行时防护不够,需从开发流程堵住源头:
- ESLint 启用
no-extend-native规则并设为error,让Array.prototype.map = ...这类代码在编辑器里就标红 - CI 流程中强制 lint 检查通过才允许合并,杜绝带污染逻辑的代码入库
- 团队规范明确写入:禁止向
Object、Array、String等原生构造器原型添加/覆盖方法
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











