반응형

리액트를 공부하면서 객체 불변성을 지켜야한다는 컨셉을 지키기 위해 좀 더 확실하게 개념을 잡을 필요가 있어서 공부하다가 정리를 해봅니다.

자바스크립트에서 객체나 배열을 복사할때 단순하게 대입연산자를 통해 처리하면 아래와 같이 같은 주소값을 바라보게 된다.

 

대입연산자를 통한 복사(참조 복사)

let obj1 = {a:1, b:2};
let obj2 = obj1;
obj2.a = 3;
console.log(obj1.a === obj2.a) //true 같은 주소값을 바라보고 있어서 같이 값이 바뀌어있다.
console.log(obj1.a) //3

obj1 생성하면서 발생한 주소값을 obj2도 바라보게 되어 값이 같이 바뀌게 된다.

즉, obj1과 obj2는 그냥 같은 값이다.

 

 

얕은 복사

ex1)

let obj1 = {a:1, b:2};
let obj2 = {...obj1};
console.log(obj1 === obj2) //false 서로 같은 주소값을 바라보진 않는다.
obj2.a = 3;
console.log(obj1.a === obj2.a) //false
console.log(obj1.a) //1

es6 문법 중 전개 연산자(...obj)를 통해 얕은 복사를 진행하였다.

 

결과만 봤을때는?

깊은 복사가 진행되었다. 단순 배열이나 단순 객체의 경우에는 깊은 복사가 진행된다.

각각의 객체가 서로 다른 값을 유지하기 때문이다.

하지만 아래와 같이 배열안에 객체들이 존재하는 경우에는 어떨까?

 

ex2)

let obj1 = [{a:1, b:2}, {a:5, b:25}];
let obj2 = [...obj1];
console.log(obj1 === obj2) //false 서로 같은 주소값을 바라보진 않는다.
obj2[0].a = 3;
console.log(obj1[0].a === obj2[0].a) //true
console.log(obj1[0].a) //3

배열안에 각각 객체들이 들어간 obj1을 복사하였다.

obj1, obj2의 배열만 비교하였을땐 서로 다른 주소값을 보도록 된 것을 볼 수 있지만, 첫번째 배열 인자의 a값을 확인해보면 true로 발생한다.

첫번쨰 인자의 객체주소값을 동일하게 obj1[0].a 와 obj2[0].a가 공유하고 있기때문이다.

마지막행에서도 바꾼적 없는 obj1[0].a 값이 3으로 나오는것을 볼 수 있다.

 

이처럼 내부의 객체나 배열등이 원본의 값을 참조하는 경우 얕은 복사(shallow copy)라고 지칭한다.

 

 

깊은 복사

let obj1 = [{a:1, b:2}, {a:5, b:25}];
let obj2 = [...obj1];
console.log(obj1 === obj2) //false 서로 같은 주소값을 바라보진 않는다.
obj2[0] = {...obj2[0],
        a : 3}; //전개 연산자를 통해 내부 특정 속성값까지 참조값을 변경한다.
console.log(obj1[0].a === obj2[0].a) //false 내부 객체의 참조값까지 변경되었다.
console.log(obj1[0].a) //1

깊은 복사의 예제이다.

 

다른 방식도 있지만 이번에도 전개 연산자(...)를 통해 처리하였다.

 

이부분이 포인트일 것이다.

obj2[0] = {...obj2[0],
        a : 3};

변경하고자 하는 요소의 참조값을 변경하여 내부까진 변경을 해야한다.

 

 

물론 아래처럼 다른 요소는 당연히 얕은 복사가 되었을 것이다.

console.log(obj1[0].b === obj2[0].b) //true

실제로 값이 필요한부분만 깊은 복사처리를 한것이고, 애초에 배열이나 객체 내부의 객체등을 깊은 복사를 하고자 할때는 JSON.stringify() 메소드는 또는 반복문을 통해 재처리가 필요할 것이다.

반응형