JavaScript 데이터 - 얕은 복사, 깊은 복사
const user = {
name: 'Riam',
age: 87,
emails: ['riam@gmail.com']
}
const copyUser = user
console.log(copyUser === user) // true
user.age = 22
console.log('user:', user.age) // user: 22
console.log('copyUser:', copyUser.age) // copyUser: 22
위의 예제에서는 user라는 객체 데이터를 하나 생성하고, copyUser에 user를 할당한다.
이렇게 하면 user와 copyUser는 같은 객체 데이터를 가리키게 된다.
따라서 user.age를 수정하더라도 copyUser.age가 같이 수정되어 22라는 값이 출력된다.
얕은 복사(Shallow copy)
const user = {
name: 'Riam',
age: 87,
emails: ['riam@gmail.com']
}
const copyUser = Object.assign({}, user)
console.log(copyUser === user) // 결과: false
user.age = 22
console.log(user) // 결과: {name: 'Riam', age: 22, emails: ['riam@gmail.com']}
console.log(copyUser) // 결과: {name: 'Riam', age: 87, emails: ['riam@gmail.com']}
user.emails.push('claudette@morrel.com')
console.log(user.emails) // 결과: ['riam@gmail.com', 'claudette@morrel.com']
console.log(copyUser.emails) // 결과: ['riam@gmail.com', 'claudette@morrel.com']
console.log(user.emails === copyUser.emails) // 결과: true
user.emails = ['Riam@tistory.com']
console.log(user.emails) // 결과: ['Riam@tistory.com']
console.log(copyUser.emails) // 결과: ['riam@gmail.com', 'claudette@morrel.com']
console.log(user.emails === copyUser.emails) // 결과: false
이번에는 Object.assign() 을 이용하여 copyUser에 user의 내용만을 복사하여 새로운 메모리 주소에 할당하였다.
따라서 user와 copyUser는 다른 메모리 주소를 가지게 되고, user.age를 수정하여도 copyUser에는 영향이 없는 것을 확인할 수 있다.
이 때 push() 메소드로 user의 email 배열 객체에 새 이메일 주소를 추가하게 되면
놀랍게도 copyUser의 email 배열 객체에도 추가가 되는 것을 볼 수 있다.
이는 "얕은 복사" 현상 때문이다.
얕은 복사는 객체의 내용은 복사하여 새로운 메모리에 할당하지만 참조 관계는 복사하지 않는다.
쉽게 말하면 객체 내부의 또 다른 객체가 있는 경우 그 객체의 변수가 가리키는 메모리를 참조하여 해당 객체 자체를 복사하는 것이 아니라, 내부 객체가 참조하는 메모리 주소만을 복사하게 된다.
따라서 내용들은 새로운 메모리 영역에 저장되지만 내부 객체들은 원본을 가리키고 있는 것이다.
이를 해결하기 위해서는 깊은 복사(Deep copy)를 해야한다.
이와 별개로 user.emails 에 대입 연산자를 통해 ['Riam@tistory.com']을 할당하게 되면
새로운 객체를 할당하는 것이므로 새로운 메모리 주소에 ['Riam@tistory.com']을 저장하게 되고 user.emails를 해당 주소로 변경하게 되므로 copyUser와 user의 emails는 다른 주소를 가리키게 된다.
깊은 복사(Deep copy)
import _ from 'lodash'
const user = {
name: 'Riam',
age: 87,
emails: ['riam@gmail.com']
}
const copyUser = _.cloneDeep(user)
console.log(copyUser === user) // 결과: false
user.emails.push('claudette@morrel.com')
console.log(user.emails) // 결과: ['riam@gmail.com', 'claudette@morrel.com']
console.log(copyUser.emails) // 결과: ['riam@gmail.com']
console.log(user.emails === copyUser.emails) // 결과: false
lodash 의 cloneDeep() 함수를 이용하면 깊은 복사를 할 수 있다.
.clone()과 비슷하지만 재귀 함수를 통해 객체 내 객체 데이터의 참조관계까지 전부 복사한다.