코어자바스크립트 스터디

코어 자바스크립트 - 1장 : 데이터 타입

려낭 2024. 7. 3. 21:28
1. 데이터 타입의 종류

 

자바스크립트 데이터 타입에는 크게 두 가지가 있다.

 

 

데이터 타입

  • 기본형
    • 숫자(Number)
    • 문자열(String)
    • 불리언(Boolean)
    • null
    • undefined
    • Symbol
  • 참조형
    • 객체(Object)
    • 함수(Function)
    • 날짜(Date)
    • 정규 표현식(RegExp)
    • Map,WeakMap
    • Set,WeakSet

 

기본형과 참조형을 구분하는 기준이 뭘까?

 

- 일반적으로 기본형은 할당이나 연산시 복제되고 참조형은 참조된다고 알려져 있음

 

엄밀히 말하면 둘 모두 복제를 하긴 하지만 기본형은 값이 담긴 주솟값을 바로 복제하는 반면,

참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다는 점이 다르다.

 


 

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

 

메모리와 데이터

 

0또는 1만 표현할 수 있는 하나의 메모리 조각을 비트(bit)라고 한다.

각 비트는 고유한 식별자를 통해 위치를 확인할 수 있다.

그러나 고작 0이나 1만 표현할 수 있는 비트 단위로 위치를 확인하는 것은 매우 비효율적이다.

자주 사용하지 않을 데이터를 표현하기 위해 빈 공간을 남겨놓기보다, 크게 문제가 되지 않을 적정한 공간을 묶는 편이 낫다.

 

>> 이런 고민의 결과로 바이트(byte)라는 단위가 생김.

 

바이트(byte)

 

1바이트는 8개의 비트로 구성

1비트마다 0또는 1의 두 가지 값을 표현할 수 있으므로 1바이트는 총 256(2^8)개이 값을 표현할 수 있다.

2바이트는 비트 16개이므로 65536(2^16)개의 값을 표현할 수 있다.

 

C/C++, 자바 등의 정적 타입 언어는 메모리의 낭비를 최소화하기 위해 데이터 타입별로 할당할 메모리 영역을 2 바이트, 4바이트 등으로 나누어 정해놓았다.

 

한편 메모리 용량이 과거보다 월등히 커진 상황에서 등장한 자바스크립트는 상대적으로 메모리 관리에 대한 압박에서 자유로워졌다. 그래서 메모리 공간을 좀 더 넉넉하게 할당했다.

 

모든 데이터는 바이트 단위의 식별자,  더 정확하게는 메모리 주솟값을 통해 서로 구분하고 연결할 수 있다.

 

 

 

식별자와 변수

 

변수

  • 변할 수 있는 수
  • 반드시 숫자여야 하는 것은 아니다
  • 컴퓨터 용어로는 '변할 수 있는 무언가' (무언가 = 데이터)

식별자

  • 어떤 데이터를 식별하는 데 사용하는 이름
  • 변수명

 


 

3.  변수 선언과 데이터 할당

 

 

 

변수 선언

 

변수 선언

var a;

 

위의 코드를 말로 풀어쓰면

"변할 수 있는 데이터를 만든다, 이 데이터의 식별자는 a로 한다" 가 된다.

변할 수 있는 데이터이기 때문에 선언할 때는 undefined이더라도 나중에 다른 값으로 바꾸면 된다.

 

변수란 결국 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇 이라고 생각하면 된다.

 

컴퓨터가 위의 명령을 받아 메모리 영역에서 수행하는 작업을 표현해보자.

 

 

 

명령을 받은 컴퓨터는 메모리에서 비어있는 공간 하나를 확보한다.

사진에서는 이의로 1003번으로 정함.

이 공간의 이름(식별자)을 a 라고 지정한다.

이후에 사용자가 a에 접근하고자 하면 컴퓨터는 메모리에서 a라는 이름을 가진 주소를 검색해 해당 공간에 담긴 데이터를 반환 할 것이다.

 

 

데이터 할당

 

변수 선언과 할당

var a;      //변수 a 선언
a = 'abc';     //변수 a에 데이터 할당

var a = 'abc';    // 변수 선언과 할당을 한 문장으로 표현

 

선언과 할당을 두 문장으로 나누어 명령하든 한 문장으로 명령하든 자바스크립트 엔진은 결국 같은 동작을 수행한다.

 

 

데이터 할당에 대한 메모리 영역의 변화

 

  1. 변수 영역에서 빈 공간(@1003)을 확보한다
  2. 확보한 공간의 식별자를 a로 지정한다
  3. 데이터 영역의 빈 공간(@5004)에 문자열 'abc'를 저장한다
  4. 변수 영역에서 a라는 식별자를 검색한다 (@1003)
  5. 앞서 저장한 문자열의 주소(@5004)를 (@1003)의 공간에 대입한다

 

왜 변수 영역에 값을 직접 대입하지 않고 굳이 번거롭게 한 단계를 더 거치는걸까?

데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위해

 

 효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 최적이다.

 

 

문자열 변환에 대한 메모리 영역의 변화

 

500개의 변수를 생성해서 모든 변수에 숫자 5를 할당하는 상황을 생각해보자

각 변수 공간마다 매번 숫자 5를 할당하려고 하면 숫자형은 8바이트가 필요하므로 4000(500*8)바이트를 써야 한다.

그 대신 5를 별도의 공간에 한번만 저장하고 해당 주소만 입력한다면?

주소 공간의 크기가 2 바이트라고 한다면 1008(500*2 +8)바이트만 이용하면 된다.

이처럼 변수 영역과  데이터 영역을 분리하면 중복된 데이터에 대한 처리 효율이 높아진다.

 


4. 기본 데이터와 참조형 데이터

 

 

불변값

 

변수와 상수를 구분하는 성질은 '변경 가능성'

 

바꿀 수 있으면 변수, 바꿀 수 없으면 상수이다.

불변값과 상수를 같은 개념으로 오해할 수 있는데 명확히 구분해야 한다.

변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이다. 

한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당 할 수 있는지 여부가 관건이다.

반면 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리이다.

 

기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변값이다.

 

var a 'abc';
a = a + 'def';

var b = 5;
var c = 5;
b = 7;

 

문자열 'abc'를 할당했다가 뒤에 'def'를 추가하면 기존의 'abc'가 'abcdef'로 바뀌는 것이 아니라 새로운 문자열 'abcdef'를 만들어 그 주소를 변수 a에 저장한다. 

'abc' 와 'abcdef'는 완전히 별개의 데이터이다.

 

변수b에 숫자 5를 할당한다. 

컴퓨터는 데이터 영역에서 5를 찾고, 없으면 데이터 공간을 하나 만들어 저장한다. 그 주소를 b에 저장하고,  다시 같은수인 5를 할당하려고 한다. 컴퓨터에서는 데이터 영역에서 5를 찾는다. 이미 만들어 놓은 값이 있으니 그 주소를 재활용한다.

 

변수b의 값을 7로 바꾸고자 한다. 

그러면 기존에 저장된 5 자체를 7로 바꾸는 것이 아니라 기존에 저장했던 7을 찾아서 있으면 재활용하고, 없으면 새로 만들어서 b에 저장한다. 결국 5와 7 모두 다른 값으로 변경할 수 없다.

 

이처럼 문자열 값도 한 번 만든 값을 바꿀 수 없고, 숫자 값도 다른 값으로 변경할 수 없다. 

이것이 바로 불변값의 성질이다. 한 번 만들어진 값은 영원히 변하지 않는다.

 

가변값

 

참조형 데이터를 변수에 할당하는 과정을 확인해보자.

 

var obj1 = {
	a:1,
    b: 'bbb'
};

참조형 데이터의 할당

  1. 컴퓨터는 우선 변수 영역의 빈 공간 (@1002)을 확보하고, 그 주소의 이름을 obj1으로 지정한다.
  2. 임의의 데이터 저장 공간 (@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소(@7103 ~?)를 @5001에 저장한다.
  3. @7103및 @7104에 각각 a와 b라는 프로퍼티 이름을 지정한다.
  4. 데이터 영역에서 숫자 1을 검색한다. 검색 결과가 없으므로 @5003에 저장하고, 이 주소를 @7103에 저장한다. 문자열 'bbb'역시 임의로 @5004에 저장하고 이 주소를 @7104에 저장한다.

 

 


5. 불변 객체

 

불변 객체를 만드는 간단한 방법

 

불변 객체는 reactmvue, angular등의 라이브러리나 프레임워크에서 뿐만 아니라 함수형 프로그래밍, 디자인 패턴 등에서도 매우 중요한 기초가 되는 개념이다.

 

참조형 데이터의 '가변'은 데이터 자체가 아닌 내부 프로퍼티를 변경할 때만 성립한다.

데이터 자체를 변경하고자 하면 기본형 데이터와 마찬가지로 기존 데이터는 변하지 않는다.

 

그렇다면 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당하기로 규칙을 정하거나 자동으로 새로운 객체를 만드는 도구를 활용한다면 객체 역시 불변성을 확보할 수 있을 것이다.

 

그럼 어떤 상황에서 불변 객체가 필요할까?

값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 종종 발생한다.

바로 이럴 때 불변 객체가 필요하다

 

 


6. undefined와 null

 

자바스크립트에는 '없음'을 나타내는 값이 두 가지가 있다.

 

바로 undefined와 null 이다. 

 

undefined는 사용자가 명시적으로 지정할 수도 있지만 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여하는 경우도 있다.

 

자바스크립트 엔진은 사용자가 응당 어떤 값을 지정할 것이라고 예상되는 상황에도 실제로 그렇게 하지 않았을 때 undefined를 반환한다.

다음 세 경우가 이에 해당한다.

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

 

-자동으로 undefined를 부여하는 경우

var a;
console.log(a);      //(1)undefined. 값을 대입하지 않은 변수에 접근

var obj = { a: 1};
console.log(obj.a);    //1
console.log(obj.b);    //(2) 존재하지 않는 프로퍼티에 접근
console.log(b);        //c.f) ReferenceError : b is not defined

var func =function() { };
var c = func();    //(3) 반환(return) 값이 없으면 undefined를 반환한 것으로 간주.
console.log(c);    //undefined

 

 

-undefined와 배열

var arr1 = [];
arr1.length = 3;
console.log(arr1);      //[empty x 3]

var arr2 = new Array(3);
console.log(arr2);     //[empty x 3]

var arr3 = [undefined, undefined, undefined];
console.log(arr3);       //[undefined, undefined, undefined]

 

1번째 줄에서 빈 배열을 만들고, 2번째 줄에서 배열의 크기를 3으로 하자 3번째 줄에서는 [empty x3]이 출력됐다. 이는 배열에서 3개의 빈 요소를 확보했지만 확보된 각 요소에는 문자 그대로 어떤 값도, 심지어 undefined 조차도 할당돼 있지 않음을 의미한다.

 

5번째 줄에서는 new 연산자와 함께 Array 생성자 함수를 호출하여 배열 인스턴스를 생성했는데, 이때 배열의 크기는 3으로 지정.

6번째 줄에서 출력된 결과는 arr1과 같다.

 

한편 8번째 줄에서는 리터럴 방식으로 배열을 생성하면서 각 요소에 undefined를 부여했다. 

9번째 줄의 출력 결과는 3번째 및 6번째 줄의 결과와 다른 것을 확인할 수 있다.

 

이처럼 비어있는 요소와 undefined를 할당한 요소는 출력 결과부터 다르다.

 

 

사용자가 명시적으로 부여한 경우와 비어있는 요소에 접근하려 할 때 반환되는 두 경우의 'undefined'의 의미를 구분할 수 있다. 

전자의 undefined는 그 자체로의 값이다. undefined가 비록 '비어있음'을 의미하긴 하지만 하나의 값으로 동작하기 때문에 이때의 프로퍼티나 배열의 요소는 고유의 키값(프로퍼티 이름)이 실존하게 되고, 따라서 순회의 대상이 될 수 있다.

 

한편 사용자가 아무것도 하지 않은 채로 접근했을 때 자바 스크립트 엔진이 하는 수 없이 반환해주는 undefined는 해당 프로퍼티 내 배열의 키값(인덱스) 자체가 존재하지 않음을 의미한다.

 

값으로써 어딘가에 할당된 undefined는 실존하는 데이터인 반면, 자바스크립트 엔젠이 반환해주는 undefined는 문자 그대로 값이 없음을 나타낸다.

 

같은 의미를 가진 null이라는 값이 별도로 있는데 굳이 undefined를 써야 할 이유가 없다.

'비어있음'을 명시적으로 나타내고 싶을 때는 undefined가 아닌 null을 쓰면 된다.

null은 애초부터 이런 용도로 만든 데이터 타입이다. 이런 규칙을 따르는 한 undefined는  값을 대입하지 않은 변수에 접근하고자 할 때 자바스크립트 엔진이 반환해주는 값으로서만 존재할 수 있다.

 

추가로 null의 주의할 점

typeof null이 object라는 점이다. 이는 자바스크립트 자체 버그이다.

따라서 어떤 변수의 값이 null인지 여부를 판별하기 위해서는 typeof 대신 다른 방식으로 접근해야 한다.

 

var n = null;
console.log(typeof n);          //object

console.log(n == undefined);    //true
console.log(n == null);         //true

console.log(n === undefined);   //false
console.log(n === null);        //true

 

4번째 줄과 같이 동등연산자(==)로 비교할 경우 null과 undefined가 서로 같다고 판단한다.

따라서 어떤 변수가 실제로 null인지 아니면 undefined인지는 동등연산자로 비교해서는 알 수 없다.

7,8번째 줄과 같이 일치 연산자(===)를 써야만 정확히 판별할 수 있다.

 

 

'코어자바스크립트 스터디' 카테고리의 다른 글

5장 클로저  (0) 2024.07.15
3,4강 발표자료  (0) 2024.07.13
4장 콜백함수  (0) 2024.07.10
3장 this  (0) 2024.07.08
1장 데이터 타입, 2장 실행 컨텍스트 발표자료  (0) 2024.07.05