앞서 살펴봤듯이 참조형 데이터의 경우 새로운 데이터를 할당할 때 단순히 메모리 주소만 변경하는 경우가 아니라면 복사라는 개념을 사용해 각각의 변수들을 구분해서 관리해야합니다.
이러한 복사라는 개념은 겉의 표면만 복사하는 얕은 복사와 내부의 모든 참조까지 새로운 메모리로 복사하는 깊은 복사로 나누게 됩니다.
Obejct.assign() 메소드나 전개 연산자(...)를 사용한 복사
const user = {
name: '0soe',
age: 12,
emails: ['0soe8@naver.com]
}
const copyUser = user
console.log(copyUser === user) // true
user.age = 22
console.log(user) // {name: '0soe', age: 12, email: array(1)}
console.log(copyUser) // {name: '0soe', age: 12, email: Array(1)}
// user와 copyUser가 바라보는 메모리 주소가 같으므로 copyUser의 age도 함께 바뀌어 있음
copyUser
와 user
는 같은 메모리 주소를 가르키고 있는 상태에서 user
의 age속성의 값을 변경하는 경우 copyUser
의 age속성의 값도 변경된 것을 확인할 수 있습니다.
※Object.assgin({}, A ) 이용
- assgin함수는 {}객체에 A가 가지고 있는 여러가지 속성들을 담아서 반환합니다.
- 현재 {}는 빈 객체이기 때문에 A와 동일한 속성을 가지고 있는 새로운 데이터를 반환하게 되는 것입니다.
const shallowUser = Object.assign({}, user)
console.log(shallowUser === user) // 값: false
console.log(shallowUser) // 값: {name: '0seo', age: 12, email: Array(1)}
※전개연산자 이용
...
를 사용하여 배열 데이터를 쉼표로 구분된 각각의 아이템으로 전개하여 출력할 수 있습니다.const B = {...A}
의 경우 새로운 {}객체 데이터에 할당이 되게 되는 것입니다.
const spreadUser = {...user}
console.log(spreadUser === user) // false
console.log(spreadUser) // {name: '0seo', age: 12, email: Array(1)}
얕은 복사의 문제점
user.emails.push('00seo23@gmail.com')
console.log(user.emails === spreadUser.emails) // 값: true
//
// 같은 메모리 주소를 바라보기 때문에 값이 true가 반환됨
user의 emails은 배열데이터 입니다. 또한 배열데이터는 참조형 데이터 중에 하나로 user.emails
과 spreadUser.emails
은 같은 메모리 주소를 바라보게 됩니다.
얕은 복사의 경우 객체데이터를 복사하는 것으로 그 안의 새로운 참조형데이터인 배열데이터까지 복사하지 못하기 때문에 user.emails
을 변경하게 되면 spreadUser.emails
도 변경되게 되는 것입니다.
깊은 복사의 경우 참조형데이터 내부에 있는 또다른 참조형데이터까지 모두 복사를 하게 됩니다. 하지만 JavaScript로 직접적으로 구현하기엔 복잡하기 때문에 Lodash 패키지를 이용하여 깊은 복사 구현해보도록 하겠습니다.
import _ from 'lodash'
const user = {
name: '0soe',
age: 12,
emails: ['0soe8@naver.com]
}
const copyUser = _.cloneDeep(user)
console.log(copyUser === user) // false
user.age = 22
console.log(user) // {name: '0seo8', age: 22, email: Array(1)}
console.log(copyUser) // {name: '0seo8', age: 12, email: Array(1)}
user.emails.push('00seo23@gmail.com')
console.log(user.emails === copyUser.emails) // 값false
console.log(user) // 값: {name: '0seo8', age: 22, email: Array(2)}
console.log(copyUser) // 값: {name: '0seo8', age: 12, email: Array(1)}
결국, 객체나 배열 데이터를 간단히 복사할 때에는 얕은 복사를 사용하되 참조형 데이터 내에 또 다른 참조형 데이터가 포함되어 있을 때에는 깊은 복사를 이용해야 합니다.