我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
var x = {'e': 2, 'd': 8, 'b': 5};
const y = {};
for(let key in x) {
y[key] = x[key];
}
console.log(y); // =>>> {e: 2, d: 8, b: 5}
const z = {};
Object.keys(x).forEach(key => {
z[key] = x[key];
});
console.log(z); // =>>> {e: 2, d: 8, b: 5}
const w = {};
for(let i = 0; i < Object.keys(x).length; i++) {
w[Object.keys(x)[i]] = x[Object.keys(x)[i]];
}
console.log(w); // =>>> {e: 2, d: 8, b: 5}
const v = {};
for(let key of Object.keys(x)) {
v[key] = x[key];
}
console.log(v); // =>>> {e: 2, d: 8, b: 5}
x['q'] = 100; // Altering x will not affect the other objects
console.log(x); // =>>> {e: 2, d: 8, b: 5, q: 100}
console.log(y); // =>>> {e: 2, d: 8, b: 5}
console.log(z); // =>>> {e: 2, d: 8, b: 5}
console.log(w); // =>>> {e: 2, d: 8, b: 5}
console.log(v); // =>>> {e: 2, d: 8, b: 5}
其他回答
这里许多同行针对深度克隆提出的解决方案JSON.parse(JSON.stringify(orig_obj)有几个问题,我发现这些问题如下:
它在复制原始对象中未定义值的条目时丢弃这些条目,如果有一些值,如Infinity、NaN等,它们将在复制时转换为null,如果原始对象中存在Date类型,则它将在克隆对象中字符串化(typeof Date_entry-->string)。
找到了一种克隆对象的有效方法,它在各种场景中都很适合我。请看一看下面的代码,因为它已经解决了JSON.parse(…)的所有上述缺陷,但最终实现了正确的深度克隆:
var orig_obj = {
string: 'my_str',
number: 123,
bool: false,
nul: null,
nested : {
value : true
},
nan : NaN,
date: new Date(),
undef: undefined,
inf: Infinity,
}
console.log("original_obj before modification: ", orig_obj, "\n");
console.log(typeof orig_obj.date, "\n");
var clone_obj = Object.assign({}, orig_obj);
//this below loop will help in deep cloning and solving above issues
for(let prop in orig_obj) {
if(typeof orig_obj[prop] === "object") {
if(orig_obj[prop] instanceof Date)
clone_obj[prop] = orig_obj[prop];
else {
clone_obj[prop] = JSON.parse(JSON.stringify(orig_obj[prop]));
}
}
}
console.log("cloned_obj before modification: ", orig_obj, "\n");
clone_obj.bool = true;
clone_obj.nested.value = "false";
console.log("original_obj post modification: ", orig_obj, "\n");
console.log("cloned_obj post modification: ", clone_obj, "\n");
console.log(typeof clone_obj.date);
为了更好地理解对象的复制,这个示例性的jsbin可能很有用
class base {
get under(){return true}
}
class a extends base {}
const b = {
get b1(){return true},
b: true
}
console.log('Object assign')
let t1 = Object.create(b)
t1.x = true
const c = Object.assign(t1, new a())
console.log(c.b1 ? 'prop value copied': 'prop value gone')
console.log(c.x ? 'assigned value copied': 'assigned value gone')
console.log(c.under ? 'inheritance ok': 'inheritance gone')
console.log(c.b1 ? 'get value unchanged' : 'get value lost')
c.b1 = false
console.log(c.b1? 'get unchanged' : 'get lost')
console.log('-----------------------------------')
console.log('Object assign - order swopped')
t1 = Object.create(b)
t1.x = true
const d = Object.assign(new a(), t1)
console.log(d.b1 ? 'prop value copied': 'prop value gone')
console.log(d.x ? 'assigned value copied': 'assigned value gone')
console.log(d.under ? 'inheritance n/a': 'inheritance gone')
console.log(d.b1 ? 'get value copied' : 'get value lost')
d.b1 = false
console.log(d.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('Spread operator')
t1 = Object.create(b)
t2 = new a()
t1.x = true
const e = { ...t1, ...t2 }
console.log(e.b1 ? 'prop value copied': 'prop value gone')
console.log(e.x ? 'assigned value copied': 'assigned value gone')
console.log(e.under ? 'inheritance ok': 'inheritance gone')
console.log(e.b1 ? 'get value copied' : 'get value lost')
e.b1 = false
console.log(e.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('Spread operator on getPrototypeOf')
t1 = Object.create(b)
t2 = new a()
t1.x = true
const e1 = { ...Object.getPrototypeOf(t1), ...Object.getPrototypeOf(t2) }
console.log(e1.b1 ? 'prop value copied': 'prop value gone')
console.log(e1.x ? 'assigned value copied': 'assigned value gone')
console.log(e1.under ? 'inheritance ok': 'inheritance gone')
console.log(e1.b1 ? 'get value copied' : 'get value lost')
e1.b1 = false
console.log(e1.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('keys, defineProperty, getOwnPropertyDescriptor')
f = Object.create(b)
t2 = new a()
f.x = 'a'
Object.keys(t2).forEach(key=> {
Object.defineProperty(f,key,Object.getOwnPropertyDescriptor(t2, key))
})
console.log(f.b1 ? 'prop value copied': 'prop value gone')
console.log(f.x ? 'assigned value copied': 'assigned value gone')
console.log(f.under ? 'inheritance ok': 'inheritance gone')
console.log(f.b1 ? 'get value copied' : 'get value lost')
f.b1 = false
console.log(f.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
console.log('defineProperties, getOwnPropertyDescriptors')
let g = Object.create(b)
t2 = new a()
g.x = 'a'
Object.defineProperties(g,Object.getOwnPropertyDescriptors(t2))
console.log(g.b1 ? 'prop value copied': 'prop value gone')
console.log(g.x ? 'assigned value copied': 'assigned value gone')
console.log(g.under ? 'inheritance ok': 'inheritance gone')
console.log(g.b1 ? 'get value copied' : 'get value lost')
g.b1 = false
console.log(g.b1? 'get copied' : 'get lost')
console.log('-----------------------------------')
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)
ES6解决方案,如果您想要(浅层)克隆类实例而不仅仅是属性对象。
var x = {'e': 2, 'd': 8, 'b': 5};
const y = {};
for(let key in x) {
y[key] = x[key];
}
console.log(y); // =>>> {e: 2, d: 8, b: 5}
const z = {};
Object.keys(x).forEach(key => {
z[key] = x[key];
});
console.log(z); // =>>> {e: 2, d: 8, b: 5}
const w = {};
for(let i = 0; i < Object.keys(x).length; i++) {
w[Object.keys(x)[i]] = x[Object.keys(x)[i]];
}
console.log(w); // =>>> {e: 2, d: 8, b: 5}
const v = {};
for(let key of Object.keys(x)) {
v[key] = x[key];
}
console.log(v); // =>>> {e: 2, d: 8, b: 5}
x['q'] = 100; // Altering x will not affect the other objects
console.log(x); // =>>> {e: 2, d: 8, b: 5, q: 100}
console.log(y); // =>>> {e: 2, d: 8, b: 5}
console.log(z); // =>>> {e: 2, d: 8, b: 5}
console.log(w); // =>>> {e: 2, d: 8, b: 5}
console.log(v); // =>>> {e: 2, d: 8, b: 5}
使用扩展语法执行对象的浅层复制。这意味着没有任何嵌套对象实例被克隆,正如您在下面的嵌套对象子实例示例中看到的那样
常量user1={name:“Alex”,地址:'公园大道15号',年龄43岁,儿童:{name:“John”}}const user2={…user1};user1.child.name='chris';console.log(用户1);console.log(用户2);
为了解决这个嵌套对象问题并执行深度复制,我们可以使用JSON.parse(JSON.stringify(someObject))
常量user1={name:“Alex”,地址:'公园大道15号',年龄43岁,儿童:{name:“John”}}const user2=JSON.parse(JSON.stringify(user1));user1.child.name='chris';console.log(用户1);console.log(用户2);