object.create(null) 创建无原型的纯净对象,避免属性名冲突和继承干扰,适合作为安全字典使用;它不继承 object.prototype 方法,需用 key in obj 或 object.hasown() 检查属性,遍历时仅返回自有属性。

使用 Object.create(null) 创建的对象没有原型(即 __proto__ 为 null,且不继承 Object.prototype 上的任何方法),因此它是一个真正“纯净”的键值对容器,适合作为字典(dictionary)或哈希表(hash map)使用,避免属性名冲突和意外继承行为。
为什么需要 Object.create(null)?
普通对象(如 {} 或 new Object())默认继承自 Object.prototype,因此自带 toString、hasOwnProperty、constructor 等方法。当用作字典时,若键名恰好与这些方法同名(例如 "toString"),就可能被覆盖或引发误判;同时遍历时(如 for...in)还会枚举出原型链上的可枚举属性(虽然原生方法默认不可枚举,但某些扩展或污染场景下仍有风险)。
Object.create(null) 绕过了原型链,从根源上杜绝了这类问题。
如何创建并安全使用纯净字典
创建后,该对象只拥有你显式设置的自有属性,没有任何继承属性:
- 用
obj[key] = value或Object.defineProperty添加键值对 - 用
obj[key]或obj.key读取(仅限合法标识符 key) - 用
delete obj[key]删除属性 - 用
key in obj判断是否存在(注意:不能用obj.hasOwnProperty(key),因为该方法不存在) - 遍历推荐用
Object.keys(obj)、Object.entries(obj)或for (const key of Object.keys(obj))—— 它们只返回对象自身的可枚举属性,且因无原型,结果完全可控
对比:{} vs Object.create(null)
假设定义 let dict1 = {} 和 let dict2 = Object.create(null):
-
dict1.toString返回函数(来自原型),dict2.toString是undefined -
'toString' in dict1为true(原型链上存在),'toString' in dict2为false(除非你手动加了dict2.toString = ...) -
dict1.hasOwnProperty('toString')为false(是继承来的),dict2.hasOwnProperty会报错(TypeError) -
Object.keys(dict1)和Object.keys(dict2)在空状态下都返回[],但一旦你设dict1.toString = 'custom',前者会包含"toString",后者不会受干扰
实用建议与注意事项
适合场景包括:事件总线的事件映射表、模块导出缓存、CSS 类名映射、AST 节点类型分发器等对键名不可控、要求绝对隔离的字典用途。
- 不要试图调用
toString()、valueOf()等方法,它们不存在;如需序列化,统一用JSON.stringify(obj)(它只处理自有可枚举属性,兼容Object.create(null)) - 检查属性存在性优先用
key in obj或Object.hasOwn(obj, key)(ES2022+,推荐,比in更精确,且不依赖hasOwnProperty) - 若需批量初始化,可用
Object.assign(Object.create(null), { a: 1, b: 2 }) - 注意:TypeScript 中需显式标注类型(如
Record<string any></string>或{ [key: string]: unknown }),否则可能提示缺少索引签名
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











