기본형의 경우 값을 복사한 다음 다른 값을 재할당할 경우에 그 식별자가 가리키는 주소값만 변경되어 문제가 없지만 참조형은 다르다 obj를 위한 메모리 공간이 따로 존재하고 만약 obj = obj2를 실행한다면 obj와 obj2는 같은 공간을 공유하게 된다 따라서 obj2의 속성값을 바꿀 경우 obj에 영향을 줄 수 있다
// user 객체를 생성
var user = {
name: 'mjm',
age: 25,
};
// 이름을 변경하는 함수, 'changeAge'을 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 age를 변경했네요! -> 가변
var changeAge = function (user, newAge) {
var newUser = user;
newUser.age = newAge;
return newUser;
};
// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 가변이기 때문에 user1도 영향을 받게 될거에요.
var user2 = changeAge(user, 35);
// 결국 아래 로직은 skip하게 될겁니다.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.age, user2.age); // 25 25
console.log(user === user2); // true
그래서 우리는 객체를 복사할 때 주소값이 아닌 내용물만 가져오려면 다른 방법이 더 필요하다
var changeAge = function (user, newAge) {
return {
name : user.name,
age : newAge,
} ;
};
일단 기본적인 원리는 객체 안에 프로퍼티가 가리키는 값만을 가져온다는 것이다
//이런 패턴은 어떨까요?
var copyObject = function (target) {
var result = {};
// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있습니다.
// 하드코딩을 하지 않아도 괜찮아요.
// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경하면
// 되겠죠!?
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}
이렇게 반복문을 이용할 수 있다 그러나 객체 안에 또 객체가 있는 중첩 객체라면
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
// console.log(result)
}
} else {
result = target;
}
return result;
}
//결과 확인
var obj = {
a: 1,
b: {
c: null,
d: [1, 2],
}
};
var obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;
console.log(obj); // { a: 1, b: { c: null, d: [ 1, 2 ] } }
console.log(obj2); // { a: 3, b: { c: 4, d: { '0': 1, '1': 3 } } }
재귀 함수를 이용할 수 있다 재귀 함수에 대한 내용은 알고 있었지만 return에만 붙여서 사용했었는데 저렇게도 할 수 있다는 생각을 가지고 여러가지 방법에 대해서 인지하고 있어야겠다
위에 재귀함수를 나름대로 실행 순서를 정리한 내 생각은 이렇다
- obj에 대한 함수 실행
- obj에 대한 함수 일시정지 > b에 대한 함수 실행
- obj에 대한 함수 일시정지 > b에 대한 함수 일시정지 > d에 대한 함수 실행
- obj에 대한 함수 일시정지 > b에 대한 함수 실행 + d에 대한 함수 종료
- obj에 대한 함수 실행 + b에 대한 함수 종료
- obj에 대한 함수 종료
- a 전달 a에 대한 함수 실행 else라서 result = target으로 마치고 다음 b 진행
- b 전달 b에 대한 함수 실행 => b는 object네 b에 대해서 반복문 실행
- c전달 c에 대한 함수 실행 else라서 result = target으로 마치고 다음 d 진행
- b안에 d 진행 => object네 d에 대해서 반복문 실행
- b안에 d[0] 복사, d[1]복사
- d 복사 종료 복사한 d 반환
- b 종료 => 복사한 b 전체 반환하고 종료
- 복사한 obj 전체 반환 종료
얕은 복사 : 참조형 변수가 가지는 주소값 묶음(별도의 메모리 공간)을 복사해서 영향을 주고 받을 수 있다
깊은 복사 : 내용물만 가져와서 서로 다른 주소값을 가지고 있어 원본 데이터에 영향을 주지 않는다
의도적으로 얕은 복사를 한 다음 프로퍼티를 추가해서 사용할 수도 있겠지만 깊은 복사로 알맹이만 빼오는 게 더 나을 것 같다
'오늘 뭐했냐 > 개발에 대한 주저리' 카테고리의 다른 글
실행 컨텍스트 (스코프, 호이스팅, 렉시컬 환경) (0) | 2023.06.13 |
---|---|
null과 undefined (0) | 2023.06.13 |
데이터 타입과 메모리 (0) | 2023.06.12 |
Set (0) | 2023.05.24 |
Map (1) | 2023.05.24 |