JavaScript中“将原型对象转为普通对象”实为剥离原型链、排除不可枚举属性的“脱壳”操作;常用Object.assign({}, proto)拷贝可枚举属性,或Object.getOwnPropertyDescriptors+Object.defineProperties保留所有自身属性并断开原型链。

JavaScript 中的原型对象(如 Object.prototype、Array.prototype 等)本身是普通对象,但它们带有特殊的内部属性(如 [[Prototype]])和不可枚举的内置方法(如 toString、hasOwnProperty)。所谓“转换成普通对象”,通常是指:**剥离原型链影响、排除不可枚举属性、获得一个干净的、可自由增删改查的纯数据对象**。这不是类型转换,而是“脱壳”或“快照”操作。
用 Object.assign 创建无原型副本
这是最常用且安全的方式:创建一个新对象,并把目标原型对象的**自身可枚举属性**拷贝过去。注意——它不会继承原型链上的方法,也不会复制不可枚举属性(比如 constructor 或 __proto__)。
示例:
const proto = Array.prototype;
const plainObj = Object.assign({}, proto);
console.log(plainObj.push); // undefined(push 是 Array.prototype 上的不可枚举方法)
console.log(plainObj.slice); // undefined
console.log(plainObj.hasOwnProperty); // undefined
这个 plainObj 是一个空对象,没有继承任何方法,也没有原型污染风险。
用 Object.getOwnPropertyDescriptors + Object.defineProperties
如果你想保留原型对象上**所有自身属性(包括不可枚举的)**,并控制是否可写/可配置,可以用这套组合。适用于需要完整“镜像”但又不想被原型链干扰的场景。
- 先获取所有自有属性描述符(含
enumerable: false的) - 再定义到一个新对象上,新对象可设为
Object.create(null)来彻底断开原型链
示例:
const proto = Object.prototype; const descriptors = Object.getOwnPropertyDescriptors(proto); const plainObj = Object.defineProperties(Object.create(null), descriptors); // 现在 plainObj 拥有 toString、valueOf 等方法,但不继承自 Object.prototype console.log(plainObj.toString()); // "[object Object]" console.log(plainObj.__proto__); // undefined(因为是 Object.create(null))
用展开运算符 {...obj}(仅限可枚举属性)
语法简洁,效果等同于 Object.assign({}, obj),只拷贝自身可枚举属性:
const plainObj = { ...Array.prototype };
// plainObj 是空对象,不含 push、map 等方法
⚠️ 注意:不能用于 null 或 undefined;对含有 Symbol 属性或访问器属性的对象也不完全可靠。
避免踩坑:这些不是“转换”,而是误解
-
JSON.parse(JSON.stringify(obj))—— 不适用:原型对象通常含函数、Symbol、循环引用,会丢失或报错 -
Object.setPrototypeOf(obj, null)—— 这只是切断原型链,原对象仍是原型对象本身,不可枚举属性和内部行为未变 -
new obj.constructor()—— 完全错误:原型对象一般没有可用构造器,或会抛错
真正需要的,是“取值快照”或“属性投影”,而不是强行改变对象本质。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











