웹/JavaScript

[Js] js에서는 얕은복사(shallow copy) ,깊은 복사(deep copy)가 어떻게 이루어질까?

wonin 2022. 10. 22. 11:41

포인터의 개념을 다시 되새기기 위해서 js에서 얕은 복사와 깊은 복사를 알아보겠습니다.

 

원시 타입에는 Number, BigInt, String, Boolean, Null, Undefined, Symbol 7개의 타입이 있습니다.

그 외 모든 데이터는 객체 타입입니다.

 

❗️얕은 복사(shallow copy)란?

const obj1 = { a: 1, b: 2};
const obj2 = obj1;

console.log( obj1 === obj2 ); // true
  • 위의 예시처럼 객체를 직접 대입하는 경우 참조에 의한 할당이 이루어지므로 둘은 같은 데이터(주소)를 가지고 있습니다.
  • 이것이 얕은 복사
const obj1 = { a:1, b:2 };
const obj2 = obj1;

obj2.a = 100;

console.log( obj1.a ); // 100
  • 위 두 객체는 같은 데이터(주소)를 가지고 있고, 그래서 같은 주소를 참조합니다.
  • 때문에 obj2의 property를 수정하고, obj1를 출력해도 obj2 값과 동일합니다.

👉 방법 1. …(spread) 연산자를 통한 복사

const obj1 = { a:1, b:2 };
const obj2 = { ...obj };

obj2.a = 100;

console.log( obj1 === obj2 ) // false
console.log( obj1.a ) // 1
  • ...(spread) 연산자를 통해 { }안에 obj1의 속성을 복사하여 obj2에 할당합니다.
  • 이제 obj1과 obj2는 다른 주소를 갖게됩니다. (그러나 딱, 1 depth 까지만)
  • 값이 변하지는 않았습니다. 완벽한 깊은 복사가 안된것이죠

Object.assign(생성할 객체, 복사할 객체) depth 1까지만 복사가 됩니다.

const object = {
    a: "a",
    number: {
        one: 1,
        two: 2,
    },
};

const copy = Object.assign({}, object);

copy.number.one = 3;

console.log(object === copy); // false
console.log(object.number.one  === copy.number.one); // true

Array.prototype.slice() depth 1까지만 복사가 됩니다.

const original = ['a',2,true,4,"hi"];
const copy = original.slice();

console.log(JSON.stringify(original) === JSON.stringify(copy)); // true

copy.push(10);

console.log(JSON.stringify(original) === JSON.stringify(copy)); // false

console.log(original); // [ 'a', 2, true, 4, 'hi' ]
console.log(copy); // [ 'a', 2, true, 4, 'hi', 10 ]

 

 

❗️깊은 복사(deep copy)란?

얇은 복사 처럼 주소를 복사해서 공유하는 것이 아니라, 아예 새로운 객체안 속성(property)만 복사 해서 사용할 수 없을까?

👉 방법 1. JSON.parse && JSON.stringify을 활용한 복사

 JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어집니다.

객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체(자바스크립트 객체)로 만들어줍니다.

이 방법이 가장 간단하고 쉽지만 다른 방법에 비해 느리다는 것과 객체가 function일 경우,  undefined로 처리한다는 것이 단점입니다.

var objA = [{ id: 1, name: "david" }];
var objB = JSON.parse(JSON.stringify(objA[0]));
objB.name = "jeff";
console.log("objB--", objB); // { id: 1, namve: 'jeff' }
console.log("objA--", objA); // [ { id: 1, name: 'david' } ]

👉 방법 2. lodash 라이브러리를 사용하기

라이브러리를 설치해야합니다. 더 쉽게 깊은 복사를 할 수 있습니다.

const deepCopy = require("lodash.clonedeep")
 
const object = {
  a: "a",
  number: {
    one: 1,
    two: 2,
  },
  arr: [1, 2, [3, 4]],
};
 
const copy = deepCopy(object);
 
copy.number.one = 3;
copy.arr[2].push(5);
 
console.log(object === copy); // false
console.log(object.number.one === copy.number.one); // false
console.log(object.arr === copy.arr); // false
 
console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] }
console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ]

기존 object와 copy한 객체의 참조주소, 메모리에 있는 값들이 아예 달라지는 것을 확인할 수 있습니다.

 

 

출처

728x90