我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。

如何正确克隆JavaScript对象?


当前回答

我已经在标量对象的情况下尝试过这一点,它对我很有用:

function binder(i) {
  return function () {
    return i;
  };
}

a=1;
b=binder(a)(); // copy value of a into b

alert(++a); // 2
alert(b); // still 1

当做

其他回答

可以使用rest运算符克隆阵列或对象

let myObj = {1: 100, 'a': 200};

let clone = {...myObj}; 

clone.a = 300;

console.log(clone.a) // Output :- 300
console.log(myObj.a) // Output :- 200

根据MDN:

如果要浅层复制,请使用Object.assign({},a)对于“深度”复制,请使用JSON.parse(JSON.stringify(a))

不需要外部库,但您需要首先检查浏览器兼容性。

为了更好地理解对象的复制,这个示例性的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 x = { a: 1 };
let y = x; // y is a reference to x, so if x changes y also changes and v/v

因此,要解决这个问题,请执行以下操作:

let y = JSON.parse(JSON.stringify(x)); //see Note below

防止引用的另一种方法是执行以下操作:

let x = { a: 1 };
let y = Object.assign({}, x); // Object.assign(target, ...sources)

y.a = 2;
console.log(x); // { a: 1 }
console.log(y); // { a: 2 }

注:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#warning_for_deep_clone

这是一个没有Object.assign()陷阱的现代解决方案(不通过引用复制):

const cloneObj = (obj) => {
    return Object.keys(obj).reduce((dolly, key) => {
        dolly[key] = (obj[key].constructor === Object) ?
            cloneObj(obj[key]) :
            obj[key];
        return dolly;
    }, {});
};