如何克隆包含 getter 和 setter 的 JavaScript 对象?
How to clone a JavaScript object including getters and setters?
在我正在进行的项目中,我需要将一个对象克隆到一个变量。
我首先尝试 - 这似乎是最明显的解决方案 - 做 var obj2 = obj1
,但我很快意识到这使得 obj2
refer obj1
,所以每当我在 obj2
中设置 属性 时,属性 也会在 obj1
中更新。好吧,我不能这样。
所以,我开始四处寻找在 JavaScript 中克隆对象的方法 - 我为此找到了多种解决方案,主要是 var obj2 = JSON.parse(JSON.stringify(obj1))
- 但这并没有保留我拥有的所有 getter 和 setter为我的对象定义!
现在对我来说最明显的解决方案似乎是首先使用上面的 JSON 技巧使 obj2
拥有 obj1
的所有属性,然后遍历所有对象getter 和 setter 并使用 Object.defineProperty()
将它们添加回来,但我还没有找到一种方法来获取对象的所有 getters/setters。
在实际层面上,不可能 100% 准确地克隆一个对象,因为 getter 和 setter(实际上还有其他函数)可能正在通过闭包访问词法范围内的私有变量。访问这样的方法将引用原始对象,而不是克隆对象。
如果(且仅当)不是这种情况,您可以枚举通过 Object.getOwnPropertyNames()
找到的所有属性(甚至是不可枚举的属性),然后为每个名称简单地获取单个 PropertyDescriptors
与 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)
);
}
来自@Alnitak,我认为这是捷径
function shallowClone(obj){
var clone = Object.create(Object.getPrototypeOf(obj));
var descriptors = Object.getOwnPropertyDescriptors(obj);
Object.defineProperties(clone, descriptors);
return clone;
}
在我正在进行的项目中,我需要将一个对象克隆到一个变量。
我首先尝试 - 这似乎是最明显的解决方案 - 做 var obj2 = obj1
,但我很快意识到这使得 obj2
refer obj1
,所以每当我在 obj2
中设置 属性 时,属性 也会在 obj1
中更新。好吧,我不能这样。
所以,我开始四处寻找在 JavaScript 中克隆对象的方法 - 我为此找到了多种解决方案,主要是 var obj2 = JSON.parse(JSON.stringify(obj1))
- 但这并没有保留我拥有的所有 getter 和 setter为我的对象定义!
现在对我来说最明显的解决方案似乎是首先使用上面的 JSON 技巧使 obj2
拥有 obj1
的所有属性,然后遍历所有对象getter 和 setter 并使用 Object.defineProperty()
将它们添加回来,但我还没有找到一种方法来获取对象的所有 getters/setters。
在实际层面上,不可能 100% 准确地克隆一个对象,因为 getter 和 setter(实际上还有其他函数)可能正在通过闭包访问词法范围内的私有变量。访问这样的方法将引用原始对象,而不是克隆对象。
如果(且仅当)不是这种情况,您可以枚举通过 Object.getOwnPropertyNames()
找到的所有属性(甚至是不可枚举的属性),然后为每个名称简单地获取单个 PropertyDescriptors
与 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)
);
}
来自@Alnitak,我认为这是捷径
function shallowClone(obj){
var clone = Object.create(Object.getPrototypeOf(obj));
var descriptors = Object.getOwnPropertyDescriptors(obj);
Object.defineProperties(clone, descriptors);
return clone;
}