copying objects in javascript - Lee-hyuna/33-js-concepts-kr GitHub Wiki
Copying Objects in JavaScript
์๋ฌธ: Copying Objects in JavaScript
๊ฐ์ฒด๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธ ๋ธ๋ก์ด๋ค. ๊ฐ์ฒด๋ ์์ฑ์ ์งํฉ์ด๋ฉฐ ์์ฑ์ ํค(๋๋ ์ด๋ฆ)์ ๊ฐ์ ์ฐ๊ฒฐ์ด๋ค. Javascript์ ์๋ ๊ฑฐ์ ๋ชจ๋ ๊ฐ์ฒด๋ ํ๋กํ ํ์
์ฒด์ธ์ ์๋จ์ ์๋ Object
์ ์ธ์คํด์ค๋ค์ด๋ค.
์๊ฐ
์์๋ค์ํผ, ํ ๋น ์ฐ์ฐ์๋ ๊ฐ์ฒด์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ง ์๊ณ , ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ ๋ง์ ํ ๋นํ๋ค. ๋ค์ ์ฝ๋๋ฅผ ์ดํด๋ณด์.
let obj = {
a: 1,
b: 2,
};
let copy = obj;
obj.a = 5;
console.log(copy.a);
// Result
// a = 5;
obj
๋ณ์๋ ์ด๊ธฐํ๋ ์ ๊ฐ์ฒด๋ฅผ ๋ด๊ณ ์๋ค. copy
๋ณ์๋ obj
๊ฐ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฅดํค๊ณ , ๊ทธ ๊ฒ์ ์ฐธ์กฐํ๊ณ ์๋ค. ๊ทธ๋ ๊ธฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก { a: 1, b: 2 }
object๋ ๋๊ฐ์ง ๋ณ์๋ฅผ ํตํด (obj, copy) ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค. obj
๋ณ์๋ copy
๋ณ์์๊ฒ ๊ฐ์ ํ ๋น ํ๋ฉด { a: 1, b: 2 }
๊ฐ์ด ๋ณ๊ฒฝ๋ ๊ฒ์ด๋ค.
Immutability(๋ถ๋ณ์ฑ)์ด๋ ๋จ์ด๊ฐ ์์ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์๋๋ฐ, ์ด๋ฅผ ์ฃผ๋ชฉํด์ผํ๋ค. ์์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ด๋ค ํํ์ ๋ถ๋ณ์ฑ์ ์ ๊ฑฐํ๋ฉฐ ์๋์ ๊ฐ์ฒด๊ฐ ์ฝ๋์ ๋ค๋ฅธ ๋ถ๋ถ์ ์ํด ์ฌ์ฉ๋ ๊ฒฝ์ฐ ๋ฒ๊ทธ๋ก ์ด์ด์ง ์ ์๋ค.
๋จ์ํ ๊ฐ์ฒด ๋ณต์ฌ ๋ฐฉ๋ฒ
๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๋จ์ํ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ์ฒด๋ฅผ ์ํ์์ผ ๊ฐ๊ฐ์ ์์ฑ์ ์ฐจ๋ก๋ก ๋ณต์ฌํ๋ ๊ฒ์ด๋ค. ์ด ์ฝ๋๋ฅผ ์ดํด๋ณด์.
function copy(mainObj) {
let objCopy = {}; // objCopy will store a copy of the mainObj
let key;
for (key in mainObj) {
objCopy[key] = mainObj[key]; // copies each property to the objCopy object
}
return objCopy;
}
const mainObj = {
a: 2,
b: 5,
c: {
x: 7,
y: 4,
},
}
console.log(copy(mainObj));
๋ด์ ๋ ๋ฌธ์ ์
- ์๋ํ ๊ฒ๊ณผ ๋ฌ๋ฆฌ,
mainObj
๊ฐ์ฒด์ ํ๋กํ ํ์ ๋ฉ์๋์ ์๋ก์ดobjCopy
์Object.prototype
๋ฉ์๋๊ฐ ์๋ก ๋ค๋ฅด๋ค. ์๋ ์๋๋ ๊ฐ์ฒด์ ์ ํํ ์ฌ๋ณธ์ ๊ฐ์ง๋ ๊ฒ์ด๋ค. - ์์ฑ ์์ ์(Property descriptors)๋ ๋ณต์ฌ๋์ง ์๋๋ค. ๊ฐ์ด false๋ก ์ค์ ๋ "writable" ์์ ์๋
objCopy
๊ฐ์ฒด์์ true๊ฐ ๋๋ค.์์ฑ ์์ ์(Property descriptors) ์ฐธ๊ณ : Object.defineProperty()
- ์์ ์ฝ๋๋
mainObj
์ ์ด๊ฑฐ๊ฐ๋ฅํ(enumerable) ์์ฑ๋ง ๋ณต์ฌํ๋ค. - ์๋ณธ ๊ฐ์ฒด์ ์์ฑ ์ค ํ๋๊ฐ ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ, ๋ณต์ฌ๋ณธ๊ณผ ์๋ณธ ๊ฐ์ ๊ณต์ ๋์ด ๊ฐ๊ฐ์ ์์ฑ์ด ๋์ผํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฅดํค๋๋ก ํ ๊ฒ์ด๋ค.
์์ ๊ฐ์ฒด ๋ณต์ฌ
์ต์ ์ ์์ฑ์ด ์๋ฌด๋ฐ ์ฐธ์กฐ ์์ด ๋ณต์ฌ๋๊ณ ๊ฐ์ด ๊ฐ์ฒด๋ก์ ์ฐธ์กฐ๋ก ๋ณต์ฌ๋๋ ์์ค ์์ฑ์ด ์กด์ฌํ ๋ ๊ฐ์ฒด๋ ์๊ฒ ๋ณต์ฌ๋๋ค๊ณ ํ๋ค. ์๋ณธ ๊ฐ์ด ๊ฐ์ฒด์ ๋ํ ์ฐธ์กฐ์ธ ๊ฒฝ์ฐ ํด๋น ์ฐธ์กฐ ๊ฐ๋ง ๋ณต์ฌ ๋๋ค.
์์ ๋ณต์ฌ๋ ์ต์์ ์์ฑ์ ๋ณต์ ํ์ง๋ง ์ค์ฒฉ๋ ๊ฐ์ฒด๋ ์๋ณธ(์์ค)๊ณผ ๋ณต์ฌ๋ณธ(๋์) ๊ฐ์ ๊ณต์ ๋๋ค.
Object.assign() ๋ฉ์๋ ์ด์ฉํ๊ธฐ
Object.assign()
๋ฉ์๋๋ ๋ชจ๋ ์ด๊ฑฐ ๊ฐ๋ฅํ ์์ฑ์ ๊ฐ์ ๋ณต์ฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
let obj = {
a: 1,
b: 2,
};
let objCopy = Object.assign({}, obj);
console.log(objCopy);
// Result - { a: 1, b: 2 }
๊ฒ์ผ๋ก ๋ณด๊ธฐ์, ์ง๊ธ๊น์ง ํ๋ ๊ฒฐ๊ณผ๋ ๋๊ฐ์ ๋ณด์ธ๋ค. ์ด๋ฏธ copy ํจ์๋ฅผ ์ด์ฉํ์ฌ obj
๋ฅผ ๋ณต์ฌ ํ์๋ค. ์์ ๋ค๋ฅด๊ฒ ๋ถ๋ณ์ฑ(immutability)์ ๊ฐ์ง๋์ง ํ์ธํด๋ณด์.
let obj = {
a: 1,
b: 2,
};
let objCopy = Object.assign({}, obj);
console.log(objCopy); // result - { a: 1, b: 2 }
objCopy.b = 89;
console.log(objCopy); // result - { a: 1, b: 89 }
console.log(obj); // result - { a: 1, b: 2 }
์์ ์ฝ๋์์, objCopy
์ b
์์ฑ ๊ฐ์ 89
๋ก ๋ณ๊ฒฝํ์๊ณ , ์ฝ์์ ์์ ๋ objCopy
๊ฐ์ ์ฐ์ด๋ณด๋ฉด ๋ณ๊ฒฝ ๋ด์ฉ์ objCopy
์๋ง ์ ์ฉ๋๋ค. ์ฝ๋ ๋ง์ง๋ง ์ค์ ๋ณด๋ฉด obj
๊ฐ์ฒด๊ฐ ์จ์ ํ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ด๋ ์๋ณธ ๊ฐ์ฒด์ ๋ํ ์ด๋ ํ ์ฐธ์กฐ๋ ์์ด ์ฑ๊ณต์ ์ผ๋ก ์ฌ๋ณธ์ ๋ง๋ค์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
Object.assign()์ ๋ฌธ์ ์
์ฑ๊ณต์ ์ผ๋ก ๋ณต์ฌ๋ณธ์ ๋ง๋ค์๊ณ ๋ชจ๋ ๊ฒ์ด ์ ๋๊ณ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์์ ๋ณต์ฌ์ ๋ํด ๋ ผ์ํ๋ ๊ฒ์ ๊ธฐ์ตํ๋๊ฐ? ์ด ์์ ๋ฅผ ์ดํด๋ณด์.
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} }
// Note: newObj.b.c = 30; Read why..
์ obj.b.c = 30 ์ผ๊น?
์ด ๊ฒ์ด Object.assign()
์ ๋ฌธ์ ์ ์ด๋ค. 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); // { c: 3 }
someObj
์obj
์ ํ๋กํ ํ์ ์ฒด์ธ์ ์กด์ฌํ๋ฏ๋ก ๋ณต์ฌ๋์ง ์๋๋ค.์์ฑ b
๋ ์ด๊ฑฐ๊ฐ๋ฅํ ์์ฑ์ด ์๋๋ค.์์ฑ c
๋ enumerable ์์ฑ ์์ ์๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๋์ ๋ณต์ฌ ๋ ๊ฒ์ด๋ค.
๊น์ ๊ฐ์ฒด ๋ณต์ฌ
๊น์ ๋ณต์ฌ๋ ๋ง์ฃผํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ๋ณต์ ํ ๊ฒ์ด๋ค. ์ฌ๋ณธ๊ณผ ์๋์ ๊ฐ์ฒด๋ ์๋ฌด๊ฒ๋ ๊ณต์ ํ์ง ์์ ๊ฒ์ด๋ฏ๋ก ์๋ณธ์ ์ฌ๋ณธ์ด ๋ ๊ฒ์ด๋ค. 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 } } (New Object Intact!)
๋ถ๋ณ์ฑ๋ ๊ฐ์ง๋ค.
JSON.parse(JSON.stringify(object))์ ๋ฌธ์ ์
๋ถํํ๊ฒ๋ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉ์ ์ ์ ๊ฐ์ฒด ๋ฉ์๋๋ฅผ ๋ณต์ฌํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ค. ์๋ ๋ด์ฉ์ ์ฐธ๊ณ ํ์.
๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ๋ณต์ฌํ๊ธฐ
ํจ์์ธ ๋ฉ์๋๋ ๊ฐ์ฒด์ ์์ฑ์ด๋ค. ์ง๊ธ๊น์ง ์์ ์์๋ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ๋ณต์ฌํ์ง ์์๋ค. ์์ผ๋ก ์์ ์์ ์ด์ ์ ๋์จ ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ๋ฉ์๋ ๋ณต์ฌ๋ฅผ ์๋ํ ๊ฒ์ด๋ค.
let obj = {
name: 'scotch.io',
exec: function exec() {
return true;
},
}
let method1 = Object.assign({}, obj);
let method2 = JSON.parse(JSON.stringify(obj));
console.log(method1); //Object.assign({}, obj)
/* result
{
exec: function exec() {
return true;
},
name: "scotch.io"
}
*/
console.log(method2); // JSON.parse(JSON.stringify(obj))
/* result
{
name: "scotch.io"
}
*/
๊ฒฐ๊ณผ๋, Object.assign()
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ์๋๋ฅผ ๋ณต์ฌํ ์ ์๋ ๋ฐ๋ฉด์ JSON.parse(JSON.stringify(obj)
์ฌ์ฉํ๋ฉด ๋ฉ์๋๋ฅผ ๋ณต์ฌํ ์ ์๋ค๋ ๊ฒ์ ๋ณด์ฌ์ค๋ค.
์ํ ๊ฐ์ฒด ๋ณต์ฌ
์ํ ๊ฐ์ฒด๋ ์์ ์ ์ฐธ์กฐํ๋ ์์ฑ์ด์๋ ๊ฐ์ฒด์ด๋ค. ์ง๊ธ๊น์ง ๋ฐฐ์ด ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ์ํ ๊ฐ์ฒด์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค๊ณ ๊ทธ๊ฒ์ด ์๋ํ๋์ง ์ดํด๋ณด์.
JSON.parse(JSON.stringify(object)) ์ฌ์ฉํ๊ธฐ
JSON.parse(JSON.stringify(object))
์ฌ์ฉํด์ ์ํ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํด๋ณด์.:
// circular object
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)
๋ ๋ถ๋ช
ํ ์ํ ๊ฐ์ฒด์ ํจ๊ณผ๊ฐ ์๋ค.
Object.assign()์ ์ฌ์ฉํ์ฌ ์ํ ๊ฐ์ฒด ๋ณต์ฌํ๊ธฐ
Object.assign()
์ฌ์ฉํด์ ์ํ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํด๋ณด์.:
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()
์ ์์ ๋ณต์ฌํ๋ ๋ฐ๋ ํจ๊ณผ๊ฐ ์์ง๋ง ๊น์ ๋ณต์ฌ์๋ ํจ๊ณผ๊ฐ ์๋ค. ๋ธ๋ผ์ฐ์ ์ฝ์์์ ์ํ ๊ฐ์ฒด ํธ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํด๋ณด์. ๊ทธ๊ณณ์์ ๋ง์ ํฅ๋ฏธ๋ก์ด ์์
์ด ์งํ๋๊ณ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋ ๊ฒ์ด๋ค.
์ ๊ฐ ๊ตฌ๋ฌธ (...) ์ฌ์ฉํ๊ธฐ
ES6์๋ ์ด๋ฏธ ๋ฐฐ์ด ํด์ฒด ํ ๋น์ ์ํ ๋๋จธ์ง ์์(rest elements)์ ๊ตฌํ๋ ๋ฐฐ์ด ๋ฆฌํฐ๋ด์ ์ํ ๋ถ์ฐ ์์(spread elements)๊ฐ ์๋ค. ์๋ ์์ ์์ ๋ฐฐ์ด์ ๋ํ ๋ถ์ฐ ์์ ๊ตฌํ์ ์ดํด๋ณด์.
const array = [
"a",
"c",
"d", {
four: 4
},
];
const newArray = [...array];
console.log(newArray);
// Result
// ["a", "c", "d", { four: 4 }]
๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ๋ํ ํ์ฐ ์์ฑ(spread property)์ ํ์ฌ ECMAScript์ ๋ํ 3๋จ๊ณ ์ ์์ด๋ค. ๊ฐ์ฒด์ ์คํ๋ ๋ ์์ฑ์ ์์ฒด ๊ฐ์ฒด์ ์ด๊ฑฐ๊ฐ๋ฅ ์์ฑ์ ์๋ณธ ๊ฐ์ฒด์์ ๋์ ๊ฐ์ฒด๋ก ๋ณต์ฌํ๋ค. ์๋์ ์์ ๋ ์ ์์ด ๋ฐ์๋ค์ฌ์ง๋ฉด ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๊ฒ์ด ์ผ๋ง๋ ์ฌ์ด์ง๋ฅผ ๋ณด์ฌ์ค๋ค.
let obj = {
one: 1,
two: 2,
}
let newObj = { ...z };
// { one: 1, two: 2 }
์ฐธ๊ณ : ์์ ๋ณต์ฌ์๋ง ํจ๊ณผ๊ฐ ์๋ค.
๊ฒฐ๋ก
JavaScript์์ ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ๋ ๊ฒ์ ์ด๋ ต๋ค. JavaScript๋ฅผ ์ฒ์ ์ ํ๊ณ ์ธ์ด๋ฅผ ๋ชจ๋ฅด๋ ๊ฒฝ์ฐ์ ๋งค์ฐ ํ๋ค ์ ์๋ค. ์ด ๊ธ์ด ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ ๋ ์ง๋ฉดํ ์ ์๋ ๋ฌธ์ ๋ฅผ ์ดํดํ๊ณ ํด๊ฒฐํ๋๋ฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋ค. ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ ์ฝ๋ ์กฐ๊ฐ์ด ์๋ค๋ฉด ๊ณต์ ํ๊ธธ ๋ฐ๋๋ค. ํดํผ์ฝ๋ฉ!