자바스크립트를 배우면서 중요한 개념이라고 할 수 있는 얕은 복사와 깊은 복사에 대해 이해하고 활용할 수 있도록 공부하려고 한다. 특히나 리액트 같은 경우는 원본 데이터를 변경하지 않고 데이터를 복사해서 새롭게 사용하기 때문에 이 개념에 대해 정확하게 알고 있어야 한다고 생각한다.
얕은 복사와 깊은 복사
복사는 그냥 = 해서 할당하면 되는 거 아닌가?라고 생각했었던 사람으로 얕은 복사와 깊은 복사는 많은 차이를 가지고 있다. 얕은 복사는 최상위 에서만 복제가 되는 것을 말하고 깊은 복사는 객체의 끝까지 모두 복사가 되는 것을 말한다. 예시 코드를 보면서 더 자세하게 살펴보자
const bookshelf1 = {
책1: "해리포터",
책컬렉션: {
소설1: "반지의제왕",
소설2: "나의라임오렌지나무"
}
};
const bookshelf2 = {...bookshelf1}; // 얕은 복사
console.log(bookshelf2.책1 === bookshelf1.책1) // true
bookshelf2.책1 = '오징어 게임'
console.log(bookshelf1.책1); // "해리포터" 그대로 유지
console.log(bookshelf2.책1) // "오징어 게임" 출력
얕은 복사는 최상위 에서만 복제가 된다고 했다. bookshelf1라는 하나의 책꽂이가 있다고 가정해 보자. 최상에서만 복제가 되니 책1을 복제를 성공했다. 책컬렉션도 복사해야 하는데 책 컬렉션은 또 다른 객체이다. 그렇기 때문에 책 컬렉션이 가지고 있던 참조를 그대로 참조하게 된다. 결과를 보면 bookshelf2의 책1을 변경해도 bookshelf1의 책1에는 아무런 변화가 없다. 하지만 아래의 코드를 보자.
const bookshelf1 = {
책1: "해리포터",
책컬렉션: {
소설1: "반지의제왕",
소설2: "나의라임오렌지나무"
}
};
const bookshelf2 = {...bookshelf1}; // 얕은 복사
bookshelf2.책컬렉션.소설1 = '바다의 왕자'
console.log(bookshelf1.책컬렉션.소설1) // 바다의 왕자
console.log(bookshelf2.책컬렉션.소설1) // 바다의 왕자
bookshelf2의 책컬렉션의 소설1번을 변경하니 bookshelf1의 책컬렉션 소설1도 함께 변경되었다. 즉 bookshelf1의 책컬렉션의 참조를 bookshelf2가 그대로 참조하고 있었다는 것을 의미한다. 이렇게 최상위만 복제되는 것을 얕은 복사라고 한다.
얕은 복사의 장점
얕은 복사를 하면 데이터를 한 곳에서 변경이 가능하고 메모리를 많이 차지하지 않기 때문에 관리를 효율적으로 할 수 있다는 장점이 있다.
얕은 복사 방법
- 스프레드 연산자
대표적인 방법으로 쉽게 얕은 복사를 할 수 있다. 코드가 간결해지고 읽기 쉽기 때문에 많이들 사용하는 방법이다.
// 배열 얕은 복사
const arr = [1, 2, 3, 4, 5]
const arr1 = [...arr]
// 객체 얕은 복사
const obj = {
name: "minhoo",
age: 30,
};
const obj1 = { ...obj };
- Object.assign( )
오랫동안 객체를 복사하기 위해 사용되었던 함수로 첫 번째 인자로 객체, 두 번째 인자로 복사할 객체를 받는다.
const obj = {
name: "minhoo",
age: 30,
};
const obj1 = Object.assgin({}, obj)
얕은 복사를 할 수 있는 대표적인 방법들을 알아보았다. 얕은 복사를 하면 좋은 점도 있지만 현재의 컴퓨터의 메모리는 메모리를 얼마나 차지하는지 걱정하지 않아도 될 정도이다. 그렇다면 깊은 복사는 어떠할까?
const person = {
name: "minhoo",
age: 30,
address: {
city: "서울",
district: "강남구"
},
};
const person2 = JSON.parse(JSON.stringify(person));
person2.address.city = '제주도'
console.log(person2.address.city) // 제주도
console.log(person.address.city) // 서울
깊은 복사는 객체의 끝까지 복사된다고 말했다. 깊은 복사는 데이터를 변경하게 되었을 때 원본 데이터에 영향을 미치지 않는 것을 확인할 수 있다.
깊은 복사의 장점
깊은 복사를 하게 되면 원본 데이터의 영향을 주지 않고 데이터를 변경할 수 있기 때문에 생각하지 못했던 데이터의 변경을 막을 수 있다. 하지만 새롭게 만들기 때문에 메모리를 차지하게 된다는 단점도 있다.
깊은 복사 방법
- JSON.parse( ), JSON.stringify( )
JSON의 메서드를 사용해서 깊은 복사를 하는 방법이다. 하지만 이 방법은 문제가 있는데 바로 함수형 데이터는 undefined가 발생한다는 것이다.
const person = {
name: "minhoo",
age: 30,
address: {
city: "서울",
district: "강남구"
},
getAddress: function() {
console.log("이건 누락")
}
};
const person2 = JSON.parse(JSON.stringify(person));
console.log(person) // {name: 'minhoo', age: 30, address: {…}}
console.log(person) // {name: 'minhoo', age: 30, address: {…}, getAddress: ƒ}
- Lodash의 cloneDeep( ) 활용
많은 개발자들이 깊은 복사를 효율적으로 사용하기 위해서 등장한 라이브러리의 메서드이다. 오랜 기간 사용되어왔고 많은 개발자들의 검증이 있었기 때문에 효율적으로 사용이 가능하다. - structuredClone( ) 함수
JSON메서드를 사용하는 방법보다 보완 된 웹 API로 많은 데이터 타입을 복사할 수 있다는 장점이 있지만 아쉽게도 JSO메서드를 사용하는 것과 같이 함수를 복사할 수 없다. 함수가 있다면 에러가 발생한다.
const person = {
name: "minhoo",
age: 30,
address: {
city: "서울",
district: "강남구"
},
getAddress: function() {
console.log("이건 누락")
}
};
const person2 = structuredClone(person)
console.log(person)
console.log(person2)
//DataCloneError: Failed to execute 'structuredClone' on 'Window': function() {
console.log("이건 누락")
} could not be cloned.
- 재귀 함수를 직접 구현
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
재귀 함수를 직접 구현해서 하나하나 복사해 주는 방식을 사용할 수 있다. 하지만 성능적인 문제 혹은 많은 데이터 타입 등의 이유로 잘 사용되지는 않는다.
필요한 상황에 알맞게 데이터를 복사하는 연습을 꾸준히 하며 익혀야 한다.
'JavaScript' 카테고리의 다른 글
HTML, CSS, JS만을 활용한 영화 검색 페이지 구현(2) (0) | 2024.10.21 |
---|---|
자바스크립트 클로저 완벽하게 이해하기 (0) | 2024.10.15 |
자바스크립트 함수 호출에 따른 this 와 명시적 바인딩 (0) | 2024.10.14 |
자바스크립트 실행 컨텍스트 복습 및 정리하기 (1) | 2024.10.11 |
자바스크립트 자료형 Set 학습 및 정리하기 (0) | 2024.10.10 |
댓글