1. 데이터 타입의 종류
- 기본형: Number, String, Boolean, Null, Undefined, Symbol
- 참조형(문자 그대로 어떤 것을 참조하고 있는 것): Object(Array, Function, Date, RegExp, Map, WeakMap, Set, WeakSet)
- 기본형과 참조형을 나누는 기준
- 값의 저장 방식
- 기본형: 값이 담긴 주소값을 바로 복제
- 참조형: 값이 담긴 주소값들로 이루어진 묶음을 가르키는 주소값을 복제
- 불변성 여부
- 기본형: 불변하다 (메모리 관점에서)
- 참조형: 불변하지 않다
2. 메모리와 데이터에 관한 배경지식
- 비트 (Bit = Binary Digit)
- 컴퓨터가 이해할 수 있는 가장 작은 단위
- 0 또는 1 두 가지 값만 가질 수 있음 (이진수 형태)
- 바이트 (Byte)
- 8개의 비트로 구성된 데이터 단위 (0과 1만 표현하는 비트를 모두 찾기는 부담)
- 메모리
- 메모리 주소값(byte 단위의 식별자)으로 구분
- 64비트를 메모리에 저장하려면
- 64bit -> 8 byte 분할
- 각각의 8개 바이트가 메모리에 저장
- 언어에 따른 메모리 관리 방식
- 자바나 C와 같은 언어는 변수형을 저장할 때 변수의 크기까지 지정해줘야 하는 경우가 있음(feat. 정수형)
- JS: let a = 8
- JAVA: keyword a = 8; (keyword에는 byte, short, int, long이 들어갈 수 있음)
3. 변수 선언과 데이터 할당
/** 선언과 할당을 풀어 쓴 방식 */
var str;
str = 'test!';
/** 선언과 할당을 붙여 쓴 방식 */
var str = 'test!';
4. 기본형 데이터와 참조형 데이터
- 메모리를 기준으로 다시 한번 생각해부는 두 가지 주요 개념
- 변수 vs 상수
- 변수: 변수 영역 메모리를 변경할 수 있음
- 상수: 변수 영역 메모리를 변경할 수 없음
- 불변하다 vs 불변하지 않다
- 불변하다: 데이터 영역 메모리를 변경할 수 없음
- 불변하지 않다: 데이터 영역 메모리를 변경할 수 있음
- 불변값과 불변성 (with 기본형 데이터)
// a라는 변수가 abc에서 abcdef가 되는 과정을 통해 불변성을 유추해봅시다!
// 'abc'라는 값이 데이터영역의 @5002라는 주소에 들어갔다고 가정할게요.
var a = 'abc';
// 'def'라는 값이 @5002라는 주소에 추가되는 것이 아니죠!
// @5003에 별도로 'abcdef'라는 값이 생기고 a라는 변수는 @5002 -> @5003
// 즉, "변수 a는 불변하다." 라고 할 수 있습니다.
// 이 때, @5002는 더 이상 사용되지 않기 때문에 가비지컬렉터의 수거 대상이 됩니다.
a = a + 'def';
- 가변값과 가변성(with 참조형 데이터)
- 기본형 데이터와 참조형 데이터의 변수 할당 과정 차이: 객체의 변수 영역의 별도 존재 여부
- 참초형 데이터가 불변하지 않다(가변하다)라고 하는 이유
- 데이터 영역에 저장된 값은 여전히 계속 불변값이지만 변수 영역이 아닌 별도 저장공간은 변경이 됨
- 중첩객체의 할당
- 중첩객체: 객체 안에 또 다른 객체가 들어가는 것
var obj = {
x: 3,
arr: [3, 4, 5],
}
// obj.arr[1]의 탐색과정은 어떻게 될까요? 작성하신 표에서 한번 찾아가보세요!
| 변수 |
주소 |
1001 |
1002 |
1003 |
| 데이터 |
obj |
|
|
| 데이터 |
주소 |
5001 |
5002 |
5003 |
| 데이터 |
3 |
4 |
5 |
| obj |
주소 |
7103 |
7104 |
7105 |
| 데이터 |
x / @5001 |
arr / 8104 |
|
| arr |
주소 |
8104 |
8105 |
8106 |
| 데이터 |
0/@5001 |
1/@5002 |
2/@5003 |
- 참조 카운트가 0인 메모리 주소의 처리
- 참초카운트?
- 객체를 참조하는 변수나 다른 객체의 수를 나타내는 값
- 쓸모없어진 객체들이 다른 곳에서 참조 되지 않기 때문에 가비지 컬렉터에 의해 메모리에서 제거 됨
- 변수 복사의 비교
// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형
// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형
| 변수 |
주소 |
1001 |
1002 |
1003 |
1004 |
| 데이터 |
a/@5001 |
obj1/@7103~ |
b/@5001 |
obj2/@7103~ |
| 데이터 |
주소 |
5001 |
5002 |
5003 |
5004 |
| 데이터 |
10 |
'ddd' |
|
|
| obj1 |
주소 |
7103 |
7104 |
7105 |
7106 |
| 데이터 |
c/@5001 |
d/@5002 |
|
|
// 복사 이후 값 변경
b = 15;
obj2.c = 20;
| 변수 |
주소 |
1001 |
1002 |
1003 |
1004 |
| 데이터 |
a/@5001 |
obj1/@7103~ |
b/@5001@5003 |
obj2/@7103~ |
| 데이터 |
주소 |
5001 |
5002 |
5003 |
5004 |
| 데이터 |
10 |
'ddd' |
15 |
20 |
| obj1 |
주소 |
7103 |
7104 |
7105 |
7106 |
| 데이터 |
c/@5001@5004 |
d/@5002 |
|
|
- 문제
- b가 a를 복사한 후, 다른 값을 가지게 됨 (a는 @5001을 바라보기 때문에 10, b는 @5003으로 15)
- 1002, 1005를 보면 obj1과 obj2가 모두 @7103를 바라보고 있음
- 이렇게 주소를 바로 복사하면 obj2를 바꾸었음에도 불구하고 obj1도 c가 @5004(즉20)으로 바뀌게 됨
// 기본형 변수 복사의 결과는 다른 값!
a !== b;
// 참조형 변수 복사의 결과는 같은 값!(원하지 않았던 결과😭)
obj1 === obj2;
b = 15;
obj2 = { c: 20, d: 'ddd'};
| 변수 |
주소 |
1001 |
1002 |
1003 |
1004 |
| 데이터 |
a/@5001 |
obj1/@7103~ |
b/@5001@5003 |
obj2/@8104 |
| 데이터 |
주소 |
5001 |
5002 |
5003 |
5004 |
5005 |
| 데이터 |
10 |
'ddd' |
15 |
20 |
aaa |
| obj1 |
주소 |
7103 |
7104 |
7105 |
7106 |
| 데이터 |
c/@5001@5004 |
d/@5002 |
|
|
| obj1 |
주소 |
8104 |
8105 |
8106 |
8107 |
| 데이터 |
c/@5004 |
d/@5005 |
|
|
- 이렇게 되면 obj1과 obj2는 완전히 다른 값을 바라보게 됨
5. 불변 객체
- 불변하다: 객체 데이터 자체를 변경(즉, 새로운 데이터를 할당)하고자 한다면 기존 데이터는 변경되지 않는다.
- 불변 객체의 필요성
- 기존: 새로운 객체를 복사를하여 속성에 접근해서 변경하는 방식
- 개선: 항상 새로운 객체를 리턴
- 데이터의 일관성을 유지하고, 의도치 않은 부작용을 방지하기 위해 중요
- 불변 객체를 사용하면 함수가 새로운 객체를 반환하여 원본 데이터를 보호하고, 코드의 가독성을 높일 수 있음
- 하지만, 하드코딩된 속성이 많아지면 코드의 유지보수와 확장성이 떨어질 수 있음 => 얕은 복사 방법 사용
- 얕은 복사
- 바로 아래 단계의 값만 복사
- 문제점: 중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티(속성)을 복사할 때, 주소값만 복사
- 깊은 복사
- 내부의 모든 값들을 하나하나 다 찾아서 모두 복사 하는 방법
- 중첩된 객체에 대한 얕은 복사: 바로 아래 단계에 대해서는 불변성을 유지하지만, 더 깊은 단계에서는 불변성을 유지하지 못함
- 중첩된 객체에 대한 깊은 복사: 1차로 얕은 복사를 수행한 후, 내부 객체들도 개별적으로 복사해야 함
- => 객체의 포로퍼티 중, 기본형 데이터는 그대로 복사 + 참조형 데이터는 다시 내부 프로퍼트를 재귀적으로 복사
- 재귀적으로 모든 프로퍼티를 복사하여 완벽한 깊은 복사 구현 가능
- JSON을 이용하는 방법
- 문자열 반환 후 새로운 객체 생성으로 독립적인 객체 생성
- 코드가 간결하고 이해하기 쉬움
- 함수나 undefined와 같은 속성 값은 복사되지 않음
- 순환 참조를 지원하지 않음
- 객체 구조가 간단하고, 함수나 undefined 속성이 없는 경우 적합
6. undefined과 null
- undefined
- 일반적으로는 값이 있어야 할 것 같은데 없는 경우, 자동으로 부여
- 변수에 값이 지정되지 않은 경우, 데이터 영역의 메모리 주소를 지정하지 않은 채 식별자에 접근 할 때
- . 이나 []으로 접근하려 할때, 해당 데이터가 존재하지 않는 경우
- return 문이 없거나 호출되지 않은 함수의 실행 결과
- null
- '없다'를 명시적(의도적)으로 표현할 때
- typeof null이 object인 것은 javascript 자체 버그