[JavaScript]얕은 복사와 깊은 복사 - lodash의 _.cloneDeep
[ 참조 값 복사 ]
객체는 변경 가능한 값(mutable value)로, 객체를 할당받은 변수(식별자)가 가리키는 메모리에는 실제 객체를 가리키는 참조 값이 저장되어 있습니다.
때문에 동일한 객체를 공유하는 여러개의 식별자(변수) 중 하나라도 객체를 수정하게 되면, 여러 식별자들은 동일한 참조 값을 가지고 있기 때문에 서로 영향을 받게 되는데요!
const user = {
name: 'Lee',
age: 20,
emails: ['abc123@gmail.com']
}
// ============ 참조 값 복사 ============
const copyUser = user;
console.log(copyUser === user) // true
user.age = 26;
console.log(user, copyUser) // 둘 다 { name: 'Lee', age: 26, emails: ['abc123@gmail.com'] }
주소 | 메모리 | |
user | 0x000000F2 | 0x00001332 |
... | ||
copyUser | 0x00000524 | 0x00001332 |
... | ||
0x00001332 | { name: 'Lee', age: 20, emails: ['abc123@gmail.com'] } |
|
이러한 현상을 방지하기 위해 우리는 참조 값이 아닌 객체 그 자체를 복사해야 합니다.
[ 얕은 복사 shallow copy ]
const shallowCopy = Object.assign({}, 원본객체)
// 또는
const shallowCopy = {...원본객체}
얕은 복사를 하게되면, 위와 같은 현상과는 달리 원시값을 갖는 프로퍼티를 수정했을 때 복사한 변수가 가리키는 객체에는 영향이 가지 않습니다.
두 변수는 서로 다른 메모리 공간에 할당되어 있는 객체에 대한 참조 값을 갖는다고 할 수 있는데요.
하지만 객체, 배열, 함수와 같이 변경 가능한 객체 타입의 값을 프로퍼티로 갖는 경우 얕은 복사는 한 단계까지만 복사하고, 객체 타입의 프로퍼티는 그대로 영향이 가게 됩니다.
객체 안의 객체 타입의 프로퍼티가 동일한 메모리 참조 값을 갖고 있기 때문입니다.
// ============ 얕은 복사 =============
// const shallowCopy = Object.assign({}, user)
const shallowCopy = {...user}
console.log(shallowCopy === user) // false
console.log(shallowCopy, user) // 둘 다 { name: 'Lee', age: 26, emails: ['abc123@gmail.com'] }
user.age = 24
console.log('user', user) // { name: 'Lee', age: 24, emails: ['abc123@gmail.com'] }
console.log('shallowCopy', shallowCopy) // { name: 'Lee', age: 26, emails: ['abc123@gmail.com'] }
user.emails.push('hello123@gmail.com')
console.log(user.emails === shallowCopy.emails) // true
console.log('user', user) // { name: 'Lee', age: 24, emails: ['abc123@gmail.com', 'hello123@gmail.com'] }
console.log('shallowCopy', shallowCopy) // { name: 'Lee', age: 26, emails: ['abc123@gmail.com', 'hello123@gmail.com'] }
[ 깊은 복사 deep copy ]
이러한 얕은 복사의 문제점을 해결하기 위해 우리는 깊은 복사를 해야합니다.
깊은 복사에 대한 메소드를 제공해주는 라이브러리는 lodash 인데요!
먼저 Node.js 환경에서 lodash 라이브러리 설치가 필요합니다.
// 터미널
$ npm init -y
$ npm i lodash // lodash 라이브러리 설치
// 개인적으로 기록해둔것이기 때문에 패스하셔도 됩니당
$ npm i -D parcel-bundler
// package.json의 "scripts"에 추가
"dev": "parcel index.html",
"build": "parcel build index.html"
// 터미널
$ npm run build // 빌드된 결과물을 dist 폴더에 저장
$ npm run dev // 개발용 서버 열기
import _ from "lodash";
const deepCopy = _.cloneDeep(원본객체);
깊은 복사는 객체에 중첩되어 있는 객체까지 모두 복사하는 것을 말합니다.
얕은 복사는 객체에 중첩되어 있는 객체의 경우 참조 값을 복사하고, 깊은 복사는 중첩되어 있는 객체까지 모두 복사해서 원시 값처럼 완전한 복사본을 만든다는 차이가 있습니다.
import _ from "lodash"
const user = {
name: 'Lee',
age: 24,
emails: ['abc123@gmail.com', 'hello123@gmail.com']
}
// ============ 깊은 복사 =============
const deepCopy = _.cloneDeep(user)
console.log(deepCopy === user) // false
console.log(deepCopy, user) // 둘 다 { name: 'Lee', age: 24, emails: ['abc123@gmail.com', 'hello123@gmail.com'] }
user.age = 40
console.log('user', user) // age: 40
console.log('deepCopy', deepCopy) // age: 24
user.emails.push('world123@gmail.com')
console.log(user.emails === deepCopy.emails) // false
console.log('user', user) // emails: ['abc123@gmail.com', 'hello123@gmail.com', 'world123@gmail.com' ]
console.log('deepCopy', deepCopy) // emails: ['abc123@gmail.com', 'hello123@gmail.com']