얕은 복사 (Shallow Clone)
const original = {
string: "hello",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean: true,
function: function () {
return "hello";
},
};
const copied = original
original.c.d = 3000
console.log(copied.c.d) // 3000
이러한 형태의 참조 복사를 하게 되면, 동일한 객체의 주소를 바라보는 변수를 하나 더 만드는 것에 지나지 않는다. 이렇게 되면 하나의 객체가 두개의 변수에 의해서 공유되는 것이다. 이 경우에는 하나의 변수를 통해서 값을 변경했을 때, 나머지 변수에도 영향을 준다. 그러므로 최대한 지양하는 것이 좋다.
const original = {
string: "hello",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean= true,
function: function () {
return "hello";
},
};
const copied = { ...original }
original.string = "bye"
original.boolean = false
original.object.c.d = 3000
copied.array.push("D")
console.log(copied.string) // "hello"
console.log(copied.boolean) // true
console.log(copied.object.c.d) // 3000
console.log(original.array) // ["A", "B", "C", "D"]
최상위 레벨의 속성만을 봤을 땐, 원본과 복사본이 서로 영향을 받지 않는 것처럼 보인다. 하지만 불린 형태와 단순 속성이 아닌 객체나 배열에선 여전히 영향을 주고 있다.
const original = {
string: "hello",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean: true,
function: function () {
return "hello";
},
};
const copied = Object.assign({}, original)
original.number = 456
original.boolean = false
copied.array.push("D")
console.log(copied.number) = 123
console.log(copied.boolean) // true
console.log(original.array) // ["A", "B", "C", "D"]
Object.assign()
를 이용한 복사 또한 전개 연산자를 사용하여 복사한 경우와 결과가 같다.
깊은 복사 (Deep Clone)
const original = {
string: "hello",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean: true,
function: function () {
return "hello";
},
};
const copied = JSON.parse(JSON.stringify(original));
original.string = "bye"
original.boolean = false
original.object.c.d = 3000
console.log(copied.string) // "hello"
console.log(copied.boolean) // true
console.log(copied.object.c.d) // 3
console.log(copied.function) // undefined
JSON.stringify()
은 자바스크립트 객체를 JSON 파일로 바꾸고, JSON.parse()
는 JSON 파일을 다시 자바스크립트 객체 형태로 바꾸어 주는 것을 말한다. 이 과정에서 객체에 대한 참조가 사라지면서, 원본과 복사본을 다르게 다룰 수 있게 된다. 하지만 이 방법은 엇밀히 말해서 완벽한 방법을 아니다. 왜냐하면 function의 경우 복사본에 undefined로 출력하기 때문이다.
const original = {
string: "hello",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean: true,
function: function () {
return "hello";
},
};
const copied = _.cloneDeep(original);
original.string = "bye"
original.boolean = false
original.object.c.d = 3000
console.log(copied.string) // "hello"
console.log(copied.boolean) // true
console.log(copied.object.c.d) // 3
Lodash는 자바스크립트 라이브러리 중의 하나이다. 물론 사용하기 위해서는 설정이 필요하다.
// In a browser
<script src="lodash.js"></script>
// Using npm
$ npm i -g npm
$ npm i --save lodash
Lodash 메서드 중에서 cloneDeep 메서드를 사용하면 깊은 복사가 가능하다.
const clone = (input) => {
const output = {};
for (let i in input) {
if (input[i] !== null && typeof input[i] === "object") {
output[i] = clone(input[i]);
} else {
output[i] = input[i];
}
}
return output;
}
const original = {
string: "abc",
number: 123,
object: {
a: 1,
b: 2,
c: {
d: 3,
},
},
array: ["A", "B", "C"],
boolean: true,
function: function () {
return "abc";
},
};
const copied = clone(original)
original.function = function () {
return "def";
};
console.log(copied.function) // function () { return "abc"; }
재귀함수를 이용해서 직접 구현도 가능하다.