【问题标题】:How to clone a JavaScript object including getters and setters?如何克隆包含 getter 和 setter 的 JavaScript 对象?
【发布时间】:2016-04-01 13:26:21
【问题描述】:

在我正在处理的项目中,我需要将一个对象克隆到一个变量中。

我第一次尝试 - 似乎是最明显的解决方案 - 做 var obj2 = obj1,但我很快意识到这使得 obj2 referobj1,所以每当我设置一个属性在obj2 中,属性也在obj1 中更新。好吧,我不能拥有那个。

因此,我开始寻找在 JavaScript 中克隆对象的方法 - 我找到了多种解决方案,主要是 var obj2 = JSON.parse(JSON.stringify(obj1)) - 但这并没有保留我为我的对象定义的所有 getter 和 setter!

现在对我来说最明显的解决方案似乎是首先使用上面的 JSON 技巧使 obj2 拥有 obj1 的所有属性,然后遍历所有对象的 getter 和 setter 并使用 @987654330 将它们添加回来@,但我还没有找到一种方法来获取对象的所有 getter/setter。

【问题讨论】:

  • 您需要在您想要的对象上创建自己的clone 方法,该方法创建一个具有相同构造函数的新对象并为其分配相同的值。
  • @AlexD lodash 的 clone 不起作用 - 就像任何非 ES5 感知的克隆函数一样,当它尝试复制由“getter”提供的属性时,它只是读取属性的当前值并存储在克隆中,而不是复制 getter 函数本身。
  • @ALexD - 是的 - Alnitak 是 100% 正确的。不复制 getter 只使用它来访问当前值并直接克隆该值...

标签: javascript javascript-objects getter-setter


【解决方案1】:

在实际层面上,不可能 100% 准确地克隆对象,因为 getter 和 setter(实际上还有其他函数)可能通过闭包访问词法范围的私有变量。访问这样的方法将引用原始对象,而不是克隆。

如果(且仅当)不是这种情况,您可以枚举通过 Object.getOwnPropertyNames() 找到的所有属性(甚至是不可枚举的属性),然后对于每个名称,只需使用 Object.getOwnPropertyDescriptor 和然后将结果字段传递给Object.defineProperty,例如:

function shallowClone(obj) {
    var clone = Object.create(Object.getPrototypeOf(obj));

    var props = Object.getOwnPropertyNames(obj);
    props.forEach(function(key) {
        var desc = Object.getOwnPropertyDescriptor(obj, key);
        Object.defineProperty(clone, key, desc);
    });

    return clone;
}

在 ES2017 中你可以do this instead:

function shallowClone(obj) {
    return Object.create(
        Object.getPrototypeOf(obj), 
        Object.getOwnPropertyDescriptors(obj) 
    );
}

【讨论】:

  • 非常感谢!这正是我一直在寻找的——我正在和另外两个人一起做这个项目,而领导者有一个严格的“无库”规则。 ;)
  • @ArthurF。请注意,此代码仅适用于 ES5 - 它不适用于 IE9 之前的任何内容(来自内存)
  • @ArthurF。我刚刚纠正了Object.create 行中的一个小错误
  • 嘿 - 很抱歉这个回复有点晚了,但作为一个 JS 新手,什么是“词法范围的私有变量”?你能举个例子吗?谢谢。 :)
  • @ArthurF。请参阅“JavaScript 闭包如何工作” - 链接到右侧“相关”下方。
【解决方案2】:

@Alnitak,我认为这是捷径

function shallowClone(obj){
 var clone = Object.create(Object.getPrototypeOf(obj));
 var descriptors = Object.getOwnPropertyDescriptors(obj);
 Object.defineProperties(clone, descriptors);
 return clone;
}

【讨论】:

  • 是的,但这仅适用于 ES2017 及更高版本,因此仅在存在 Object.gteOwnPropertyDescriptors() 时才有效,例如 Edge
  • 对不起,我无法跟踪所有 Edge 版本...以上是正确的答案跳 Edge 一天赶上
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 2013-02-01
  • 2023-04-01
相关资源
最近更新 更多