일지/JAVA

[JavaScript] 얕은 복사, 깊은 복사

닉닉눅 2022. 11. 15. 15:32
728x90
반응형

전개 구문에 대해서 조사할 때 잠깐 나왔던 얕은 복사와 깊은 복사의 개념에 대해서 알아보고자 한다.


#얕은 복사

얕은 복사는 객체의 참조값(주소 값)을 복사하고, 깊은 복사는 원시값을 복사하여 완전한 복사를 하는것을 말한다.

 

let obj1 = { name: 'Yang', age: 25 };
let obj2 = obj1;
console.log(obj1); // { name: 'Yang', age: 25 }
console.log(obj2); // { name: 'Yang', age: 25 }

console.log( obj1 === obj2 ); //true

obj2.name = 'Hong';
console.log(obj1); // { name: 'Hong', age: 25 }
console.log(obj2); // { name: 'Hong', age: 25 }
// 얕은 복사이므로 obj2가 변경되면 같은 주소를 가지는 obj1도 바뀐다.

위의 예제처럼 객체를 직접 대입하여 얕은 복사를 하면 둘은 같은 주소 값을 가지게 되어 한쪽이 변경되면 따라서 값이 변하게된다.

#깊은 복사

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

이런 깊은 복사를 사용하기 위한 방법으로는 재귀함수를 이용한 복사, JSON.stringify(), Lodash 라이브러리를 사용하는 방법이있다.

1. JSON.stringify()

- JSON 문자열로 변환했다가 다시 객체로 변환해주기 때문에 객체에 대한 참조가 없어진다.

- 다른 방법에 비해서 성능적으로 느리다.

- function을 undefined로 처리한다. 따라서 obj2에서는 sayHello 라는 함수가 복사되지 않았다.

const obj1 = {
	age: 25,
	name: {
		first: 'Yang',
		last: 'Hong'
	},
    sayHello: () => {
		console.log('hello world!');
	},
};

const obj2 = JSON.parse(JSON.stringify(obj1));

obj1.age = 30;
obj1.name.first = 'Quokka';

console.log(p1); // { age: 30, name: { first: "Quokka", last: "Hong" }, sayHello: f };
console.log(p2); // { age: 20, name: { first: "Yang", last: "Hong" } };

 

2. 재귀함수를 이용한 복사

- 직접 구현하여 사용하기 때문에 복잡하다.

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); // 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 ] ] }

3. Lodash 라이브러리 사용

- 라이브러리를 사용하면 더 쉽게 깊은 복사를 할 수 있다.

- function도 함께 복사된다.

const clonedeep = require("lodash.clonedeep");

const obj1 = {
	age: 20,
	name: {
		first: 'Yang',
		last: 'Hong'
	},
	sayHello: () => {
		console.log('hello world!');
	},
}

const obj2 = clonedeep(obj1);

obj1.age = 30;
obj1.name.first = 'Quokka';

console.log(obj1); // { age: 30, name: { first: "Quokka", last: "Hong" }, sayHello: f };
console.log(obj2); // { age: 20, name: { first: "Yang", last: "Hong" }, sayHello: f };
obj2.sayHello(); // hello world!

※전개 구문을 사용할 경우

전개 구문은 1 레벨 깊이에서는 깊은 복사가 이루어 지지만 다차원 배열 / 2 레벨 이상의 깊이를 가진 객체는 얕은 복사를 하는 것을 알아야한다.

var arr = [1, 2, 3];
var arr2 = [...arr]; // arr.slice() 와 유사
arr2.push(4);

// arr2 은 [1, 2, 3, 4] 이 됨
// arr 은 영향을 받지 않고 남아 있음

---------------------------------------------------------------

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// 이제 배열 a 도 영향을 받음: [[], [2], [3]]

 

728x90
반응형