우선 코드부터 확인해보겠습니다.
var user = {
name: 'Jungsoo',
urls: {
naver: 'https://naver.com',
insta: 'https://insta.com'
}
}; // 객체 정의
var copyObject = function(target){
var result = [];
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}; // 객체 복사 함수 생성
var user2 = copyObject(user); // 객체 복사
user2.name = 'Jung'; // 기본형 타입 프로퍼티 변경
console.log(user.name === user2.name); // false, 불변성 성립
user2.urls.naver = 'https://www.naver.com'; // 참조형 타입 프로퍼티 변경
console.log(user.urls.naver === user2.urls.naver); // true, 불변성 성립 X
한 단계 더 들어간 urls의 내부 프로퍼티들은 기존 데이터를 그대로 참조하는 현상이 발생합니다.
이와 같이 바로 아래 단계의 값만 복사하는 것을 얕은 복사(shallow copy)라고 합니다.
이는 깊은 단계의 참조형 데이터를 복사할 때 불변성이 지켜지지 않습니다.
var user2 = copyObject(user); // 객체 복사
user2.urls = copyObject(user.urls); // 참조형 타입 복사
user2.urls.naver = 'https://www.naver.com'; // 참조형 타입 프로퍼티 변경
console.log(user.urls.naver === user2.urls.naver) // false, 불변성 성립
이처럼 참조형 데이터는 그 내부 프로퍼티들을 다시 복사해야합니다.
이를 재귀적으로 처리하면 아래와 같이 작성할 수 있습니다.
var copyObjectDeep = function(target){
var result = {};
if (typeof target === 'object && target !== null){
for (var prop in target){
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
typeof
명령어는null
값에 대해서도object
를 반환하는 버그가 있기에
object
임을 확인하는 동시에null
이 아닌지도 확인해야 합니다.
이처럼 내부의 모든 값을 하나하나 찾아서 복사하는 것을 깊은 복사(deep copy)라고 합니다.
또한 JSON으로 변환 후 복사를 진행해도 깊은 복사가 가능합니다.
var copyObjectViaJSON = function(target){
return JSON.parse(JSON.stringify(target));
}
다만 메서드(함수)
, __prote__
, getter/setter
등과 같이 JSON으로 변경할 수 없는 프로퍼티들을 모두 무시하기 때문에 순수한 정보만 다룰 때 이용하면 좋습니다.