We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
改自 https://scotch.io/bar-talk/copying-objects-in-javascript
一个对象就是一组属性值的集合,一组属性值关联着一对 Key 与 Value。在 JavaScript 中,几乎所有的对象都来自于 Object,它在原型链的顶端
Object
分配符(=)并不会真正拷贝一个对象,它仅仅拷贝了对象的 引用:
=
let obj = { a: 1, b: 2 } let copy = obj obj.a = 5 console.log(copy.a) // 输出 5
变量copy引用该对象,因此对象{a: 1, b: 2}标明:有两种方式(obj或者copy)操作我,不管操作哪一个都会改变我
copy
{a: 1, b: 2}
obj
循环原对象,拷贝它的每一个属性:
function copy(mainObj) { let objCopy = {} let key for (key in mainObj) { objCopy[key] = mainObj[key] } return objCopy } const mainObj = { a: 2, b:5, c: { x: 7, y: 4 } } console.log(copy(mainObj))
objCopy
mainObj
Object.prototype
false
writable
true
在没有任何引用的情况下复制源顶级属性时,对象被称为浅层复制,并且存在一个源属性,其值为对象并作为引用复制。如果源值是对象的引用,则它仅将该引用值复制到目标对象。
浅拷贝将复制顶级属性,但嵌套对象在原始(源)和副本(目标)之间共享。
Object.assign()方法用来拷贝一个或多个源对象自身所拥有的(不包含原型链)且可枚举属性到目标对象
Object.assign()
let obj = { a: 1, b: 2 } let objCopy = Object.assign({}, obj) console.log(objCopy) // 输出:{a: 1, b: 2} objCopy.b = 89 console.log(objCopy) // 输出:{a: 1, b: 89} console.log(obj) // 输出:{a: 1, b: 2}
上方代码中,我们实现了对obj的拷贝,当改变了对象objCopy中b属性的值为89并打印它后,发现本次修改只针对于对象objCopy,没有改变对象obj。这表明我们成功的从原对象生成了一个拷贝对象,并且没有拷贝其引用。
b
别着急,尽管看上去一切都没问题,但是还记得我们说过的浅拷贝吗?看下面的例子:
let obj = { a: 1, b: { c: 2 } } let newObj = Object.assign({}, obj) console.log(newObj) // 输出:{a: 1, b: {c: 2}} obj.a = 10 console.log(obj) // 输出:{a: 10, b: {c: 2}} console.log(newObj) // 输出:{a: 1, {b: {c: 2}}} newObj.a = 20 console.log(obj); // { a: 10, b: { c: 2} } console.log(newObj); // { a: 20, b: { c: 2} } newObj.b.c = 30 console.log(obj); // { a: 10, b: { c: 30} } console.log(newObj); // { a: 20, b: { c: 30} }
当执行obj.b.c = 30后,对象obj与对象newObj的对象属性b的属性c值均发生了改变,这是因为Object.assign方法仅实现了浅拷贝。newObj.b与obj.b都引用了同一个对象,而不是单独对值进行复制。任何对引用值得改变都会影响引用它的其它对象。
obj.b.c = 30
newObj
c
Object.assign
newObj.b
obj.b
注意:在原型链上的属性或者不可枚举的属性都不会被拷贝
let someObj = { a: 2 } let obj = Object.create(someObj, { b: { value: 2 }, c: { value: 3, enumerable: true } }) let objCopy = Object.assign({}, obj) console.log(objCopy)
对象someObj
对象obj
属性 b
属性 c
深拷贝将复制它遇到的每个对象,副本和原始对象不会共享任何内容,因此它将是原始副本。下面我们解决下使用Object.assign()进行浅拷贝遇到的问题:
JSON.parse(JSON.stringify(object))
这解决了我们之前遇到的问题。 现在newObj.b有副本而不是引用! 这是深拷贝对象的一种方法:
let obj = { a: 1, b: { c: 2 } } let newObj = JSON.parse(JSON.stringify(obj)) obj.b.c = 20 console.log(obj); // { a: 1, b: { c: 20 } } console.log(newObj); // { a: 1, b: { c: 2 } }
但是上述方法不适用于拷贝用户定义的对象内方法
方法是作为函数对象的属性,我们尝试拷贝对象内方法:
let obj = { name: 'jjzhiyuan', exec: function() { return true } } let method1 = Object.assign({}, obj) let method2 = JSON.parse(JSON.stringify(obj)) console.log(method1) // 输出 /* * { * exec: function exec() { * return true * }, * name: "jjzhiyuan" * } */ console.log(method2) // 输出 /* * { * name: "jjzhiyuan" * } */
结果显示:Object.assign()方法可以用于拷贝对象内方法,JSON.parse(JSON.stringify(obj))无法拷贝
JSON.parse(JSON.stringify(obj))
指存在引用自身属性的对象,我们尝试实现对其的拷贝:
let obj = { a: 'a', b: { c: 'c', d: 'd', }, } obj.c = obj.b; obj.e = obj.a; obj.b.c = obj.c; obj.b.d = obj.b; obj.b.e = obj.b.c; let newObj = JSON.parse(JSON.stringify(obj)); console.log(newObj);
输出如下: 因此 JSON.parse(JSON.stringify(obj))不能用于拷贝嵌套对象
let obj = { a: 'a', b: { c: 'c', d: 'd', }, } obj.c = obj.b; obj.e = obj.a; obj.b.c = obj.c; obj.b.d = obj.b; obj.b.e = obj.b.c; let newObj2 = Object.assign({}, obj); console.log(newObj2);
输出如下: Object.assign()可以实现对嵌套对象的浅拷贝
const array = [ "a", "c", "d", { four: 4 }, ]; const newArray = [...array]; console.log(newArray); // 输出 // ["a", "c", "d", { four: 4 }]
对象初始值设定项中的Spread属性将源对象中的自身可枚举属性复制到目标对象上:
let obj = { one: 1, two: 2, } let newObj = { ...obj } // { one: 1, two: 2 }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
改自 https://scotch.io/bar-talk/copying-objects-in-javascript
一个对象就是一组属性值的集合,一组属性值关联着一对 Key 与 Value。在 JavaScript 中,几乎所有的对象都来自于
Object
,它在原型链的顶端介绍
分配符(
=
)并不会真正拷贝一个对象,它仅仅拷贝了对象的 引用:变量
copy
引用该对象,因此对象{a: 1, b: 2}
标明:有两种方式(obj
或者copy
)操作我,不管操作哪一个都会改变我幼稚的拷贝对象方式
循环原对象,拷贝它的每一个属性:
存在的问题
objCopy
存在一个不同于对象mainObj
原型的Object.prototype
,这不是我们想要得到的。我们希望拷贝一个完整的原对象false
的writable
描述符,在对象objCopy
中将为true
mainObj
的可枚举属性浅拷贝
在没有任何引用的情况下复制源顶级属性时,对象被称为浅层复制,并且存在一个源属性,其值为对象并作为引用复制。如果源值是对象的引用,则它仅将该引用值复制到目标对象。
浅拷贝将复制顶级属性,但嵌套对象在原始(源)和副本(目标)之间共享。
使用 Object.assign() 方法
Object.assign()
方法用来拷贝一个或多个源对象自身所拥有的(不包含原型链)且可枚举属性到目标对象上方代码中,我们实现了对
obj
的拷贝,当改变了对象objCopy
中b
属性的值为89并打印它后,发现本次修改只针对于对象objCopy
,没有改变对象obj
。这表明我们成功的从原对象生成了一个拷贝对象,并且没有拷贝其引用。别着急,尽管看上去一切都没问题,但是还记得我们说过的浅拷贝吗?看下面的例子:
当执行
obj.b.c = 30
后,对象obj
与对象newObj
的对象属性b
的属性c
值均发生了改变,这是因为Object.assign
方法仅实现了浅拷贝。newObj.b
与obj.b
都引用了同一个对象,而不是单独对值进行复制。任何对引用值得改变都会影响引用它的其它对象。注意:在原型链上的属性或者不可枚举的属性都不会被拷贝
对象someObj
在对象obj
原型链上,它不会被拷贝属性 b
是不可枚举属性属性 c
存在可枚举属性描述符,因此它可以被拷贝深拷贝
深拷贝将复制它遇到的每个对象,副本和原始对象不会共享任何内容,因此它将是原始副本。下面我们解决下使用
Object.assign()
进行浅拷贝遇到的问题:使用
JSON.parse(JSON.stringify(object))
这解决了我们之前遇到的问题。 现在
newObj.b
有副本而不是引用! 这是深拷贝对象的一种方法:但是上述方法不适用于拷贝用户定义的对象内方法
拷贝对象方法
方法是作为函数对象的属性,我们尝试拷贝对象内方法:
结果显示:
Object.assign()
方法可以用于拷贝对象内方法,JSON.parse(JSON.stringify(obj))
无法拷贝拷贝嵌套对象
指存在引用自身属性的对象,我们尝试实现对其的拷贝:
使用
JSON.parse(JSON.stringify(object))
输出如下:
因此
JSON.parse(JSON.stringify(obj))
不能用于拷贝嵌套对象使用
Object.assign()
输出如下:
Object.assign()
可以实现对嵌套对象的浅拷贝使用 扩展运算符(...)
对象初始值设定项中的Spread属性将源对象中的自身可枚举属性复制到目标对象上:
The text was updated successfully, but these errors were encountered: