[javascript] 얕은복사 & 깊은복사

최준호·2022년 8월 7일
0

얕은 복사(shllow 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 = 10;

console.log(obj1 === obj2); // 10
  • 위 두 객체는 같은 주소를 가지고 있기에 같은 주소를 참조한다.
  • obj2의 property를 수정, obj1를 출력해도 obj2 값과 동일하다.

Object.assing()

object.assign() 매서드는 출저 객체들의 모든 열거 가능한 자체속 성을 복사하여 대상 객체에 붙여넣는다. 그 후 대상 객체를 반환한다.

Object.assign(target, ...sources)
// target: 목표 객체. 출처 객체의 속성을 복사해 반영한 후 반환할 객체
// sources: 출처 객체. 목표 객체에 반영하고자 하는 속성들을 갖고 있는 객체들
const object1 = { name: 3,
               id: 
                {a:1 
                 b:2}};

const object2 = Object.assign({}, object);
object2.word.a = "7";

console.log(object === object2); // false
console.log(object.word.a === object2.word.a); // true

console.log(object); // { name: '3', word: { a: '7', b: '2' } }
console.log(object2); // { name: '3', word: { one: '7', two: '2' } }

<복사된 객체와 원래의 객체는 depth1까지는 다른 주소를 가리키지만 depth2부터는 같은 주소를 참조하기 때문에 깊은 복사가 필요하다>

spread 연산자

object = {...복사할 객체} 형태로 쓰인다. object 뿐 아니라 배열에도 사용된다.

const object1 = { name: 3,
               id: 
                {a:1 
                 b:2}};

const object2 = {...object};
object2.word.one = "7";

console.log(object === object2); // false
console.log(object.word.a === object2.word.b); // true

console.log(object); // { name: '3', word: { one: '7', two: '2' } }
console.log(object2); // { name: '3', word: { one: '7', two: '2' } }

깊은복사(Deep Copy)

  • 깊은 복사된 객체는 객체안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말한다.

JSON.parse && JSON.stringify

  •  JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어진다.
    객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체로 만들어야한다.
    이 방법이 가장 간단하고 쉽지만 다른 방법에 비해 느리다는 것과 객체가 function일 경우,  undefined로 처리한다는 것이 단점이다.
const object = {  a: "a",  number: {    one: 1,    two: 2,  },  arr: [1, 2, [3, 4]],}; 
const copy = JSON.parse(JSON.stringify(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 ] ] }

재귀 함수

  • 코드가 복잡하드는 것이 단점이다
const object = {  
  a: "a",  
  number: {    
    one: 1,
    two: 2, 
  },  arr: [1, 2, [3, 4]],
};

function deepCopy(object) {
  if (object === null || typeof object !== "object") {
    return object;  
  }  // 객체인지 배열인지 판단  
  const copy = Array.isArray(object) ? [] : {};
  
  for (let key of Object.keys(object)) {  
    copy[key] = deepCopy(object[key]);
  }   
  return copy;}

const copy = deepCopy(object);

copy.number.one = 3;
copy.arr[2].push(5); 

console.log(object === copy); // fals
econsole.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 ] ] }

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 ] ] }
profile
LV2 프론트엔드 엔지니어

0개의 댓글