object.create(null) 仅创建原型为 null 的空对象,无法克隆属性;纯净克隆需组合 object.create(null) 与 object.assign,以获得无原型污染且含源对象自身可枚举属性的新对象。

直接用 Object.create(null) 创建新对象,不是克隆——它不复制原对象的属性,只生成一个原型为 null 的空壳。所谓“纯净对象克隆”,核心诉求其实是:**既要保持无原型链的纯净性,又要完整复制源对象自身可枚举属性**。这无法靠单参数 Object.create(proto) 一步完成,必须组合使用。
为什么单参数 Object.create 不能直接克隆
Object.create(proto) 的唯一作用是设置新对象的 [[Prototype]],它不会读取、遍历或拷贝任何属性。传入 null 只能得到一个空且无原型的对象;传入普通对象(如 {a:1})则新对象会继承其原型,但自身仍无自有属性——这不符合“克隆”定义。
真正高效的纯净克隆方案:Object.create(null) + Object.assign
这是目前最简洁、性能好、语义清晰的写法:
-
先创建纯净容器:用
Object.create(null)确保目标对象无任何原型方法干扰 -
再批量赋值:用
Object.assign(target, source)把源对象所有**自身可枚举属性**复制过去 - 零依赖、无循环、不深拷贝:适用于扁平配置、路由表、字典缓存等典型场景
示例:
const original = { name: 'admin', role: 'editor', 'hasOwnProperty': true };
const cleanClone = Object.assign(Object.create(null), original);
console.log(cleanClone.name); // 'admin'
console.log(cleanClone.hasOwnProperty); // true(作为数据键存在,不会触发原型方法)
console.log(cleanClone.toString); // undefined(无原型污染)
注意边界:哪些操作必须改写
克隆后的对象仍是纯净的,因此以下常用模式需调整:
- 判断键是否存在 → 改用
key in cleanClone(in是语言级操作,不依赖原型) - 遍历所有键 → 用
Object.keys(cleanClone)或for (const k of Object.keys(cleanClone)) - 避免
cleanClone.hasOwnProperty(key)→ 会报错,不可用 - 需要类型标识时 → 不能依赖
Object.prototype.toString.call(cleanClone),建议额外加$$type: 'dict'字段
不推荐的“伪克隆”做法
这些方式看似省事,实则引入冗余或风险:
-
Object.setPrototypeOf({}, null):语义模糊、性能较差,部分引擎可能降级优化 -
JSON.parse(JSON.stringify(obj)):丢失函数、undefined、Symbol;无法处理循环引用;且结果仍是继承Object.prototype的普通对象 -
Object.assign({}, obj):克隆出的对象仍有完整原型链,不纯净










