全量原型属性快照导出需递归遍历原型链,用object.getprototypeof获取每级原型,object.getownpropertynames与getownpropertysymbols联合采集所有自有属性名(含不可枚举及symbol),去重合并后统一用object.getownpropertydescriptor提取完整描述符,并记录isextensible/issealed/isfrozen状态。

要实现全量原型属性快照导出,关键不是“完美”而是“准确覆盖所有自有属性 + 原型链上可枚举/不可枚举属性”,而 Object.getPrototypeOf 和 Object.getOwnPropertyNames 是核心工具,但需配合递归遍历原型链,并注意属性描述符、不可枚举性、访问器属性等细节。
理解两个方法的分工
Object.getPrototypeOf(obj) 获取对象直接原型(即 obj.__proto__),是遍历原型链的入口;Object.getOwnPropertyNames(obj) 返回对象自身所有属性名(含不可枚举属性),但不包括 symbol 属性(需用 Object.getOwnPropertySymbols 补齐)。
- 仅靠
getOwnPropertyNames只能拿到当前对象的自有属性,无法触达原型上的属性 - 仅靠
getPrototypeOf不提取属性,必须搭配属性获取方法才能“看到”内容 - 二者组合,才能逐层向上采集原型链上每一级的自有属性
递归收集全部原型层级的自有属性名
从目标对象开始,沿 __proto__ 向上遍历,对每一层调用 Object.getOwnPropertyNames,并去重合并(避免 Object.prototype 等公共原型重复采集)。
- 终止条件:遇到
null(即到达原型链顶端) - 需用 Set 或 Map 记录已处理的原型引用,防止循环原型链(如手动篡改
__proto__导致环) - 推荐先收集所有属性名,再统一读取描述符,避免多次访问同一属性引发副作用(尤其访问器属性)
完整导出属性描述符而非仅名称
仅导出属性名意义有限。应使用 Object.getOwnPropertyDescriptor 对每个属性名获取完整描述符(value/writable/enumerable/configurable/get/set),这样才能还原属性行为(比如 getter 是否依赖 this 上下文)。
- 对函数、正则、日期等特殊对象,其原型属性(如
String.prototype.trim)也应被纳入快照 - 注意:访问器属性(get/set)的值不能直接读取,需在快照中标记为
{ get: [function], set: [function] }形式 - 若需序列化,函数体通常不可 JSON 化,可保留 toString() 字符串或标记为不可序列化
补全 Symbol 属性与不可扩展/冻结状态
Object.getOwnPropertyNames 忽略 Symbol 属性,必须显式调用 Object.getOwnPropertySymbols 并合并;同时快照应记录对象自身的 isExtensible、isSealed、isFrozen 状态,这对还原行为至关重要。
- Symbol 属性同样存在于原型上,需在每层原型上调用
getOwnPropertySymbols - 冻结状态影响后续修改能力,属于对象元信息,应在快照顶层字段中声明
- 建议结构:{ names: [], symbols: [], descriptors: {}, state: { extensible, sealed, frozen } }











