오늘은 JS 3주차 강의를 들었는데, 너무 어려운 부분이었다. 시작은 데이터타입으로 해서 ERD를 작성할 때 어느정도 공부하였기에 다소 잘 이해가 갔다. 하지만 불변성 부분이 나오면서 이해가 힘들어졌다. 그 내용을 정리해보며 복습해보려 한다.
* 데이터타입 : 구분 기준은 값의 저장방식과 불변성 여부
- 기본형(Number, String, Boolean, null, undefined, Symbol) : 원시형이라고도 함.
- 참조형(Array, Function, Date, RegExp, Map/WeakMap, Set/WeakSet) = 객체(Object)
=> 구분기준
1. 복제의 방식
1) 기본형 : 값이 담긴 주소값을 바로 복제
2) 참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리치는 주소값을 복제
2.불변성 여부
1) 기본형 : 불변성을 띔.
2) 참조형 : 불변성을 띄지 않음
1. 메모리의 주요 개념
1) 변수 vs 상수
1)) 변수 : 변수 영역의 메모리를 변경할 수 있음
2)) 상수 : 변수 영역의 메모리를 변경할 수 없음
2)불변하다 vs 불변하지 않다
1))불변하다 : 데이터 영역 메모리를 변경할 수 없음
2)) 불변하지 않다 : 데이터 영역 메모리를 변경할 수 있음
2. 불변성과 가변성
// abc라는 값이 데이터 영역의 @5002라는 주소에 들어갔다고 가정
var a = 'abc';
// def라는 값이 @5002라는 주소에 추가되는 것이 아니라 @5003에 별도로 'abcdef'라는 값이 생기고
// 변수 a는 @5002 -> @5003 즉, "변수 a는 불변하다."라고 할 수 있다.
// 이 때, 변수 @5002는 더 이상 사용되지 않기 때문에 가비지컬렉터가 수거함.
a = a + 'def';
*참조형 데이터는 별도 저장공간이 필요합니다!
데이터 영역에 저장된 값은 여전히 계속 불변값이지만, obj1을 위한 별도 영역은 얼마든지 변경 가능. = 가변하다.
1) 변수 복사의 비교
- 기본형 : 서로 다른 데이터 영역의 주소를 바라보고 있기 때문에 영향없음
- 참조형 : 같은 주소를 바라보고 있기 때문에 같이 변경이 됨.
2) 불변객체의 필요성
불변성이 필요한 객체가 가변성을 띠면서 함께 변하게 되면 불필요한 영향을 주고 받는 것이다.
// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수, 'changeName'을 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름을 변경했네요! -> 가변
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 가변이기 때문에 user1도 영향을 받게 될거에요.
var user2 = changeName(user, 'twojang');
// 결국 아래 로직은 skip하게 될겁니다.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // twojang twojang
console.log(user === user2); // true
3) 개선안
1)) 복사 이후 값 변경 (객체의 프로퍼티에 접근하는 것이 아니라, 아예 새로운 객체를 반환)
새로운 객체를 만들기 위해 변경할 필요가 없는 프로퍼티를 하드코딩으로 입력하게 되고 그 갯수가 많다면 작업량이 많아지고 유지보수가 어렵다.
// user 객체를 생성
var user = {
name: 'wonjang',
gender: 'male',
};
// 이름을 변경하는 함수 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티에 접근하는 것이 아니라, 아에 새로운 객체를 반환 -> 불변
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender,
};
};
// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 불변이기 때문에 user1은 영향이 없어요!
var user2 = changeName(user, 'twojang');
// 결국 아래 로직이 수행되겠네요.
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // wonjang twojang
console.log(user === user2); // false 👍
2)) 얕은 복사 (for ~ in을 통한 복사) : 바로 아래 단계의 값만 복사
중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때 주소값만 복사
//이런 패턴은 어떨까요?
var copyObject = function (target) {
var result = {};
// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있습니다.
// 하드코딩을 하지 않아도 괜찮아요.
// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경하면
// 되겠죠!?
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}
3)) 깊은 복사 (재귀적 수행을 통한 복사, 가장 이상적) : 객체의 프로퍼티 중 기본형 데이터는 그대로 복사 + 참조형 데이터는 다시 그 내부의 프로퍼티를 복사.
*재귀적 수행 => 함수나 알고리즘이 자기 자신을 호출하며 반복적으로 실행되는 것을 말한다.
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;
}
4)) JSON을 통한 복사 : JSON.stringify() 함수를 사용하여 객체를 문자열로 변환한 후, 다시 JSON.parse() 함수를 사용하여 새로운 객체를 생성하기 때문에 독립적으로 존재하여 서로 영향을 끼치지 않는다.
-장점: 코드가 간결하고 쉽게 이해할 수 있다.
-단점: 원본 객체가 가지고 있는 데이터중 함수나 undefined와 같은 속성값은 복사되지 않는다.
그리고 JSON.stringify() 함수는 순환참조를 지원하지 않아 객체가 중첩되어 있는 경우 사용할 수 없다.
'Sparta > TIL' 카테고리의 다른 글
24.01.08 TIL - This(1) (1) | 2024.01.08 |
---|---|
24.01.05 누네띠조 5일차 - 실행 컨텍스트 (0) | 2024.01.05 |
24.01.02 누네띠조 2일차 - ES6 (0) | 2024.01.02 |
23.12.29 누네띠조 1일차 - 경험의 중요성 (1) | 2024.01.02 |
23.12.28 미니프로젝트 마지막날 (3) | 2024.01.02 |