자바스크립트 데이터 타입에는 크게 두가지가 있는데, Primitive Type(원시 타입)과 Reference Type (참조 타입)이 그것이다.
let a = 123;
let b = a;
console.log(a === b); //true
a = 0;
console.log(a === b); //false
원시타입(숫자, 문자열, 불린, null, undefined) 데이터는 원본 a의 값(value)을 사본 b에 = 을 이용해서 대입했을 때,
원본 a 의 값을 변경해도 b의 값이 변경되지 않는다.
이는 원시타입 데이터는 변수에 할당될 때 메모리 상에 고정된 크기로 "새로" 저장되기 때문에, 변수가 선언(let이나 var로 생성했을 때),
초기화(최초로 변수에 값을 지정함), 할당(변수에 = 을 사용해서 값을 지정)시에 해당 메모리 영역에 직접적으로 접근한다.
한마디로 원시타입 데이터가 들어있는 변수는 고정 크기를 갖는 메모리의 어떤 부분에 저장되고, 새로운 변수가 이미 있던 변수의 값과 같은 값을 갖는다고 하더라도 새로운 변수는 원본 변수와 같은 값을 갖기만 할 뿐 원래있던 변수의 메모리나 값에 어떤 상관관계가 없는 독립적인 변수다.
그렇기 때문에 원본 변수가 변경되거나 사라져도 영향을 받지 않는다.
결론적으로 원시타입은 똑같은 값을 갖는 새로운 메모리 영역을 갖기 때문에 복사할 때 얕은 복사나 깊은 복사를 구분할 필요가 없다.
참조형 데이터타입의 얕은 복사와 깊은 복사
문제는 객체, 배열, 함수와 같은 참조형 데이터 타입의 복사다.
'코어 자바스크립트'에선 둘을 이렇게 정리했다.
얕은복사 - 바로 아래단계의 값만 복사
깊은복사 - 내부의 모든 값들을 하나하나 찾아서 전부 복사
얕은복사
let object = {
name : "john",
likes : {
food : "banana",
color : "yellow"
}
}
let object2 = object;
위처럼 참조형 데이터타입의 변수는 새로만든 변수에 같은 값을 대입하게 되면
사본 객체는 새로운 메모리 영역에 같은 값을 갖는게 아니라 원본 변수의 메모리 주소를 갖게된다. 이를 참조한다고 하는데,
사본 객체는 원본 객체의 메모리를 참조하고 있기 때문에 원본 객체가 수정되면 그 값을 가져다 쓰는 사본객체도 값이 바뀌게 된다.
반대도 마찬가지다.
'코어 자바스크립트'에서는 원본 객체의 키값 위의 예제에서는 object.name, object.likes 를 순회하며 새로운 객체 {} 를 선언하고 대입했다.
이 방법 또한 얕은 복사를 수행했다. 새로운 객체를 선언했기 때문에 원본객체의 name을 수정해도 사본객체의 name은 바뀌지 않는것을 확인할 수 있다. 하지만, 중첩된 객체 likes의 값은 원본객체를 수정하면 사본객체도 수정되게 된다.
이처럼 얕은 복사는 중첩된 객체를 온전히 복사하지 못한다.
깊은복사
let copyObjectDeep = function(target) {
let result = {};
if(typeof target === 'object' && target !== null) {
for (let prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
위는 깊은 복사를 수행하는 범용 함수다. target !== null 조건은 typeof 명령어가 null에 대해서 'object'를 반환하기 때문
깊은 복사는 원본 객체 내부에서 중첩객체를 포함한 '모든' 값을 복사하기 때문에
결론적으로 원본객체와 사본객체가 독립적으로 작동할 수 있다. (원본 객체가 변경되어도 사본객체가 변경되지 않는다. 중첩객체라 할지라도)
깊은복사 함수에서 재귀하는 부분을 제거하고 result[prop] = target[prop]으로 작성하면 얕은복사 함수가 된다.
깊은 복사를 수행하는 한가지 간단한 방법이 있는데
객체를 JSON 으로 표현된 문자열로 전환했다가 다시 JSON 객체로 복원하는 것이다.
문자열은 원시타입이기 때문에 값 자체 복사가 가능하고 이를 다시 JSON 객체로 복원하면 객체 그대로 사용할 수 있다.
단, 이 방법은 객체내부 메서드, __proto__, getter/setter 등과같은 JSON으로 변경할 수 없는 프로퍼티는 무시한다.
function (target) {
return JSON.parse(JSON.stringify(target));
}
JSON 형식을 이용한 객체의 깊은 복사
'개발서적 > 코어 자바스크립트' 카테고리의 다른 글
undefined 와 null 의 차이 (0) | 2021.03.17 |
---|
댓글