不能。object.getownpropertydescriptors仅读取getter描述符而不执行,克隆后this指向新对象,若新对象缺依赖属性则失效;深拷贝工具如clonedeep、structuredclone默认忽略accessor属性,json.stringify和object.assign也无法保留getter。

Object.getOwnPropertyDescriptors 能否直接克隆 getter?
不能。它只读取描述符,不执行 getter 函数本身,更不会把 getter 的返回值“固化”到新对象上。如果你直接用 Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj)),新对象的 getter 会照常存在,但它的 this 指向可能错乱——尤其当原 getter 内部依赖 this 访问其他属性时。
为什么 cloneDeep 也救不了带 getter 的对象?
主流深拷贝工具(如 Lodash 的 cloneDeep、structuredClone)默认忽略 accessor 属性(即 get/set)。它们只处理 value 和 writable 类型的属性,遇到 get 描述符直接跳过,结果就是目标对象里根本没这个属性。
-
structuredClone抛出DATA_CLONE_ERR错误(Chrome/Firefox 中对含 getter 的对象) -
JSON.stringify完全丢弃 getter,连同 undefined、function、Symbol 一并消失 -
Object.assign只复制可枚举自有属性,且只取 getter 的执行结果(即调用一次),不保留 getter 本身
手动重建 accessor 的关键三步
必须拆解描述符、判断类型、按需重建。核心是区分 value 型和 get/set 型,并确保 newTarget 的 this 绑定正确:
- 遍历
Object.getOwnPropertyDescriptors(source)获取所有描述符 - 对每个 key,检查描述符是否有
get或set字段;有则保留原函数,但注意:若 getter 内部用到了this.xxx,它在新对象上运行时this就是新对象,只要新对象也有对应属性,就自然可用 - 用
Object.defineProperty(target, key, descriptor)逐个定义,不能用Object.defineProperties批量——因为后者不保证定义顺序,而某些 getter 依赖其他属性已存在
示例:
const source = {
_name: 'Alice',
get name() { return this._name.toUpperCase(); }
};
const target = {};
const descriptors = Object.getOwnPropertyDescriptors(source);
for (const [key, desc] of Object.entries(descriptors)) {
Object.defineProperty(target, key, desc); // 直接复用,不改写 get/set
}
// ✅ target.name === 'ALICE',且仍是响应式 getter
getter 依赖外部状态时怎么办?
如果 getter 读取的是闭包变量、模块级 const,或绑定到特定实例的方法(比如 class 实例里的 get fullName() { return this.firstName + ' ' + this.lastName; }),那单纯复制描述符就够用了——只要新对象也有 firstName 和 lastName 属性,getter 就能正常工作。
但若 getter 依赖了不可移植的状态(如 document.body、window.location、某个全局计数器),那就不是克隆问题,而是设计问题:这种 getter 本就不该被“克隆”,而应被重构为纯函数或通过依赖注入解耦。
真正容易被忽略的是:getter 函数体内的 this 是动态的,你无法靠复制函数文本来锁定它;它永远指向调用时的宿主对象。所以“完美克隆”的前提,是你已经确保新对象具备 getter 所需的所有上下文属性。










