일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- localstorage
- til
- 브라우저
- 알고리즘
- react
- TypeScript
- v9
- state
- 자바스크립트
- 타입스크립트
- JS
- 원티드
- 리액트
- es6
- Component
- 파이어베이스
- 비트 연산자
- firebase
- Frontend
- JavaScript
- react localStorage
- CORS
- Reducer
- array
- 컴포넌트
- Redux
- axios
- 프론트엔드
- 프로그래머스
- 프리온보딩
- Today
- Total
도리쓰에러쓰
[JavaScript] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) 본문
1. 얕은 복사(Shallow Copy)
얕은 복사(Shallow Copy)는 참조값의 복사를 나타낸다.
const obj = { a: 1 };
const copyObj = obj;
copyObj.a = 2;
console.log(obj.a); // 2
console.log(obj === copyObj); // true
obj라는 객체를 copyObj라는 객체에 복사하여 copyObj.a값을 변경하였더니 기존의 obj.a값도 같이 변경되었다.
마찬가지로 두 객체를 비교해봐도 true가 나온다.
이렇게 자바스크립트의 참조 타입은 얕은 복사(Shallow Copy)가 된다고 볼 수 있으며,
이는 데이터가 그대로 생성되는 것이 아닌 해당 데이터의 참조 값을 전달하여 한 데이터를 공유하는 것이다.
2. 깊은 복사 (Deep Copy)
깊은 복사는 얕은 복사(Shallow Copy)처럼 참조값이 복사되는 것이 아니라, 값만 복사되는 것을 의미한다.
const a = 1;
const b = a;
b = 2;
console.log(a); // 1
console.log(b); // 2
console.log(a === b); // false
위 코드는 변수 a 에 1을 할당하고, 변수 b 에 a 의 값을 할당한 코드이다.
변수 b 의 값을 변경하여도 기존의 a 의 값은 변경되지 않는다.
두 값을 비교하여도 false가 출력되며 서로의 값은 단독으로 존재한다는 것을 알 수 있다.
위 예제처럼 자바스크립트의 원시 타입은 깊은 복사(Deep Copy)가 되며,
이는 독립적인 메모리에 값 자체를 할당하여 생성하는 것이라고 볼 수 있다.
💡 객체의 깊은 복사
객체를 그대로 복사하여 사용하면 기존 객체의 데이터가 변경될 수 있기 때문에
객체의 값을 복사하여 사용하고 싶다면 얕은 복사(Shallow Copy)가 아닌 깊은 복사(Deep Copy)를 사용하는 것이 좋다.
지금부터 객체를 깊이 복사하는 방법은 무엇이 있는지 알아보자.
1️⃣ Object.assign()
- 문법: Object.assign(생성할 객체, 복사할 객체);
const obj = { a: 1 };
const copyObj = Object.assign({}, obj);
copyObj.a = 2;
console.log(obj); // { a: 1 }
console.log(obj === copyObj); // false
위 예제는 copyObj라는 객체를 Object.asign() 메소드를 사용하여 생성한 코드이다.
copyObj.a 값을 변경하여도 기존의 obj.a의 값이 바뀌지 않았다.
서로의 객체를 비교해도 false가 뜨며 서로 참조값이 다른 것을 알 수 있다.
📍 Object.assign()은 2차원 객체를 복사하였을 때 깊은 복사가 이루어지지 않는다 !
const obj = {
a: 1,
b: { c: 2 },
}
const copyObj = Object.assign({}, obj);
copyObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 3 } }
console.log(obj.b.c === copyObj.b.c); // true
위 예제는 obj라는 2차원 객체를 copyObj에 복사하고 copyObj.b.c 값을 변경한 예제이다.
기존 obj 객체를 출력해보면 Object.assign() 메서드를 사용하여 객체를 복사하였음에도 불구하고 값이 변경됐다.
이는 복사된 하위 객체 { c: 2 }도 결국 객체이기 때문에 얕은 복사(Shallow Copy)가 된 것이다.
그래서 Object.assign() 메서드는 1차원 객체만 깊은 복사(Deep Copy)해야하며, 전개 연산자(Spread Operator)도 마찬가지이다.
2️⃣ 전개 연산자(Spread Operator)
const obj = {
a: 1,
b: { c: 2 },
};
const copyObj = {...obj};
copyObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 3 } }
console.log(obj.b.c === copyObj.b.c); // true
전개 연산자(Spread Operator)도 Object.assign()과 마찬가지로 2차원 객체는 얕은 복사(Shallow Copy)가 되는 것을 확인할 수 있다.
3️⃣ JSON의 stringify()와 parse()
- stringify() 문법: JSON.stringify() 메소드는 객체를 인수로 받으며 받은 객체는 문자열로 치환
- parse() 문법: JSON.parse() 메소드는 문자열을 인수로 받으며 받은 문자열은 객체로 치환
const obj = {
a: 1,
b: { c: 2 },
};
const copyObj = JSON.parse(JSON.stringify(obj));
copyObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 } }
console.log(obj.b.c === copyObj.b.c); // false
위 예제는 obj 객체를 JSON.stringify() 메소드를 이용하여 문자열로 변환한 뒤
다시 JSON.parse() 메소드를 통해 객체로 변환한 예제이다.
2차원 객체도 깊은 복사(Deep Copy)가 되긴 하지만 2가지 문제가 있다.
1) 다른 방법에 비해 성능이 느리다.
2) JSON.stringify() 메소드는 함수를 만났을 때 undefined로 처리된다.
아래 예제 코드를 확인해보자.
const obj = {
a: 1,
b: { c: 2 },
func: function() {
return this.a;
}
};
const copyObj = JSON.parse(JSON.stringify(obj));
console.log(copyObj.func); // undefined
복사된 copyObj는 func가 없고 undefined로 출력되고 있다.
4️⃣ 커스텀 재귀 함수
객체의 깊은 복사(Deep Copy)를 위해 직접 커스텀 재귀 함수를 구현하는 방법도 있다.
const deepCopy = (obj) => {
if (obj === null || typeof obj !== 'object') return obj;
let copy = {};
for (let key in obj) {
copy[key] = deepCopy(obj[key]);
}
return copy;
};
const obj = {
a: 1,
b: { c: 2 },
func: function () {
return this.a;
}
};
const copyObj = deepCopy(obj);
copyObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 }, func: [Function: func] }
console.log(obj.b.c === copyObj.b.c); // false
deepCopy() 함수로 obj 객체를 매개변수로 보낸 다음 인수값이 객체가 아닌 경우엔 그냥 반환하며,
객체인 경우 객체의 값 만큼 루프를 돌고 재귀를 호출하여 복사된 값을 반환한다.
복사된 copyObj 객체를 확인해보면 2차원 객체의 값도 깊은 복사(Deep Copy)가 되었으며, 객체의 함수도 제대로 출력되는 것을 확인할 수 있다.
5️⃣ lodash 라이브러리의 cloneDeep()
lodash 라이브러리의 cloneDeep() 메소드를 이용해 객체의 깊은 복사(Deep Copy)가 가능하다.
해당 라이브러리를 설치했다는 가정 하에 아래 코드를 확인해보자.
const obj = {
a: 1,
b: { c: 2 },
func: function () {
return this.a;
}
};
const copyObj = lodash.cloneDeep(obj);
copyObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 }, func: [Function: func] }
console.log(obj.b.c === copyObj.b.c); // false
lodash 라이브러리의 cloneDeep() 메소드를 이용하면 깊은 복사를 간편하게 구현할 수 있다.
'JavaScript > JS' 카테고리의 다른 글
[JavaScript] 자바스크립트에서의 Promise (0) | 2022.08.15 |
---|---|
[JavaScript] 실행 컨텍스트(Execution Context)란? (0) | 2022.08.10 |
[JavaScript] this란? (0) | 2022.08.05 |
[JavaScript] 주로 사용하는 문자열 메서드 모음 (String Method Collection) (0) | 2022.03.23 |
[JavaScript] 밀리초 일, 시, 분, 초 계산하기 (D-day 기능 구현) (0) | 2022.03.16 |