코어 자바스크립트 (1. 데이터 타입)

문린이·2022년 10월 25일
0

1-1 데이터 타입의 종류

  • 기본형(복제) : 숫자, 문자열, 불리언, null, undefined, 심볼
  • 참조형(참조) : 객체, 배열, 함수, 날짜, 정규표현식, Map, WeakMap, Set, WeakSet

심볼이 뭐지...?
-> 심볼은 값으로 익명의 객체 속성(object property)을 만들 수 있는 특성을 가진 원시 데이터 형식이다. (유일무이한 식별자를 만드는 데 사용)

const one = Symbol("hi");
const two = Symbol("hi");
console.log(one === two); // false

ex) API 상태 관련 변수 값

export const apiStatus = {
  IDLE: Symbol('IDLE'),
  PENDING: Symbol('PENDING'),
  SUCCESS: Symbol('SUCCESS'),
  ERROR: Symbol('ERROR')
}

1-2 데이터 타입에 관한 배경지식

변수 VS 식별자

  • 변수는 변할 수 있는 수로 변할 수 있는 데이터
    -> 변경 가능한 데이터가 담길 수 있는 공간
  • 식별자는 어떤 데이터를 식별하는 데 사용하는 이름 즉, 변수명

1-3 변수 선언과 데이터 할당

let a;
a = "abc";
a = "abcd";

라고 a를 설정했을 때 메모리 영역은 어떻게 변할까?

주소(변수) 1002 1003 1004 1005
데이터(변수) 이름 : a
값 : @5004 -> @5005
주소(데이터) 5002 5003 5004 5005
데이터(데이터) "abc" "abcd"
  1. 변수 영역에서 빈 공간(@1003)을 확보

  2. 확보한 공간의 식별자를 a로 지정

  3. 데이터 영역의 빈 공간(@5004)에 문자열 "abc"를 저장

  4. 변수 영역에서 a라는 식별자 검색(@1003)

  5. 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입

  6. 데이터 영역의 빈 공간(@5005)에 문자열 "abcd"를 저장

  7. 변수 영역에서 a라는 식별자 검색(@1003)

  8. 앞서 저장한 문자열의 주소(@5005)를 @1003의 공간에 대입

이렇게 하는 이유는?
-> 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위해!
-> 중복된 데이터에 대한 처리 효율 상승

1-4 기본형 데이터와 참조형 데이터

불변 값 VS 가변 값

1-1에서 말한 기본형 데이터는 모두 불변 값이다. 이유는 1-3에서 설명했듯이 값을 바꾸어도 데이터 영역에서 새로 생성하기 때문이다.

그럼 참조형 데이터는 어떨까? 결론부터 말하자면 가변 값이다.(따로 설정하지 않으면)

let obj1 = {
	a = 1,
  	b = "bbb"
};
obj1.a = 2;
주소(변수) 1002 1003 1004 1005 1006
데이터(변수) 이름 : obj1
값 : @5002
주소(데이터) 5002 5003 5004 5005 5006
데이터(데이터) @7103 ~ ? 1 "bbb" 2

주소(객체 @5001의 변수) 7103 7104 7105 7106 7107
데이터(객체 @5001의 변수) 이름 : a
값 : @5004 -> @5006
이름 : b
값 : @5005

변수 obj1이 바라보고 있는 주소 @5002는 변하지 않았다.
즉, 새로운 객체가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀐 것이다.

중첩된 참조형 데이터

let obj = {
	x = 3,
  	arr = [3, 4, 5]
};
  1. 변수 영역에서 빈 공간(@1002)을 확보하고 그 주소의 이름을 obj로 지정

  2. 데이터가 객체이므로 별도의 변수 영역(@7103 ~ ?)을 마련하고 그 영역의 주소를 @5001에 저장

  3. @7103에 이름 x를 @7104에 이름 arr을 지정

  4. 데이터 영역에서 숫자 3 검색 -> 없으므로 @5002에 저장하고 이 주소를 @7103에 저장

  5. @7104에 저장할 값은 배열이므로 별도의 변수 영역(@8104 ~ ?)을 마련하고 그 영역의 주소(@8104 ~ ?)를 @5003에 저장하고 @5003을 @7104에 저장

  6. 배열의 요소가 3개이므로 3개의 변수 공간을 확보하고 각각 인덱스를 부여(0, 1, 2)

  7. 데이터 영역에서 숫자 3을 검색(@5002) 있으므로 그 주소를 @8104에 저장

  8. 숫자 4는 없으므로 @5004에 저장 -> @8105에 저장

  9. 숫자 5도 없으므로 @5005에 저장 -> @8106에 저장

주소(변수) 1001 1002 1003 1004 1005
데이터(변수) 이름 : obj
값 : @5001
주소(데이터) 5001 5002 5003 5004 5005
데이터(데이터) @7103 ~ ? 3 @8104 ~ ? 4 5

주소(객체 @5001의 변수) 7103 7104 7105
데이터(객체 @5001의 변수) 이름 : x
값 : @5002
이름 : arr
값 : @5003

주소(배열 @5003의 변수) 8104 8105 8106
데이터(배열 @5003의 변수) 이름 : 0
값 : @5002
이름 : 1
값 : @5004
이름 : 2
값 : @5005

그렇다면 obj.arr[1]을 검색하면 그 과정은 어떻게 될까?

  1. obj라는 식별자를 가진 주소를 찾음(@1002)

  2. 값이 주소이므로 그 주소로 이동(@5001)

  3. 값이 주소이므로 그 주소로 이동(@7103 ~ ?)

  4. arr이라는 식별자를 가진 주소를 찾음(@7104)

  5. 값이 주소이므로 그 주소로 이동(@5003)

  6. 값이 주소이므로 그 주소로 이동(@8104 ~ ?)

  7. 인덱스 1에 해당하는 주소로 이동(@8105)

  8. 값이 주소이므로 그 주소로 이동(@5004)

  9. 값이 숫자형 데이터이므로 4를 반환

만약 여기서 obj.arr = "str"; 처럼 재할당을 내리면 어떻게 될까?

@5006에 문자열 "str"을 저장하고 그 주소를 @7104에 저장한다.

그렇게 된다면 @5003과 @8104 ~ ?은 참조 카운트가 0이 되고 가비지 컬렉션(GC)의 수거 대상이 된다.

수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 된다.

가비지 컬렉션(GC)은 뭐지...?
-> 메모리 관리 기법 중의 하나로, 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제하는 기능
mark-and-sweep라고 불리는 알고리즘을 활용한다.

기본형과 참조형 데이터의 차이점

let a = 10;
let b = a;

let obj1 = { c: 10, d: "ddd" };
let obj2 = obj1;

b = 15;
obj2.c = 20;

console.log(a); // 10
console.log(b); // 15
console.log(obj1); // { c: 20, d: 'ddd' }
console.log(obj2); // { c: 20, d: 'ddd' }

console.log(a === b); // false
console.log(obj1 === obj2); // true

변수 a와 b는 서로 다른 주소를 바라보게 됐으나 변수 obj1과 obj2는 여전히 같은 객체를 바라보고 있기 때문이다.

기본형은 값을 복사하고 참조형은 주솟값을 복사한다고 알고 있지만 이는 틀린 내용이다.
어떤 데이터 타입이든 변수에 할당하기 위해서는 주솟값을 복사해야 하기 때문이다.
다만 기본형은 주솟값을 복사하는 과정이 한 번만 이뤄지고, 참조형은 한 단계를 더 거치게 된다는 차이가 있다.

추가

obj2.c = 20; 처럼 내부 프로퍼티를 변경할 때가 아닌 obj2 = {c : 20, d : "ddd"}를 변경하면 기본형 데이터처럼 값이 달라진다.
즉, 참조형 데이터가 가변 값이라고 설명할 때의 가변은 내부의 프로퍼티를 변경할 때만 성립된다.

1-5 불변 객체

앞에서 말한 거처럼 내부 프로퍼티를 변경하면 원본 객체도 변하게 된다. 이런 현상을 방지하기 위해 불변 객체가 필요하다.
-> 라이브러리나 object.assign 등의 메서드가 사용될 수 있다.
-> 또한, 다양한 얕은 복사, 깊은 복사, 함수를 통해 표현할 수 있다.

1-6 undefined와 null

없음을 나타내는 값은 undefined와 null이 있다. undefined는 어떤 변수에 값이 존재하지 않을 경우를 의미하고 null은 사용자가 명시적으로 '없음'을 표현하기 위해 대입한 값
-> 없음을 표현하고 싶을 때는 undefined가 아닌 null을 사용하자

undefined

  • 값을 대입하지 않은 변수, 즉 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때
  • 객체 내부의 존재하지 않는 프로퍼티에 전급하려고 할 때
  • return 문이 없거나 호출되지 않는 함수의 실행 결과
let a;

let obj = { c: 10 };

let func = function () {};
let c = func();

console.log(a); // undefined

console.log(obj.c); // 10
console.log(obj.d); // undefined
console.log(objj); // ReferenceError: objj is not defined

console.log(c); // undefined
profile
Software Developer

0개의 댓글