본문 바로가기

웹/JavaScript

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

포인터의 개념을 다시 되새기기 위해서 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