데이터 타입 - 코어자바스크립트 스터디

이상철·2021년 12월 13일
0
post-thumbnail

데이터 타입

기본형

  1. 숫자
  2. 문자
  3. 불리언
  4. Null
  5. Undefined
  6. Symbol

참조형

  1. 객체 (Object)
  2. 배열 (Array)
  3. 날짜 (date)
  4. 정규 표현식 (RegExp) 등등

여기서 궁금증이 생기는 부분은 어떤 기준으로 이 둘을 구분할까요 ?
=>
기본형은 값이 담긴 주솟값을 바로 복제하는 반면,
참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가르키는 주소값을 복제합니다.

  • 기본형은 불변성을 띈다.

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

메모리와 데이터

0 또는 1로만 표현할 수 있는 하나의 메모리 조각을 bit 라고 한다.
메모리는 매우 많은 비트들로 구성되어 있는데 각 비트는 고유한 식별자를 통해
위치를 확인할 수 있다.
매우 많은 비트를 한 단위로 묶으면, 검색시간도 줄이고 표현 가능한 데이터 갯수도 늘어나지만 동시에 낭비되는 비트가 생긴다!
그래서 표현 가능한 개수에 따라서 어느정도 제약이 따르더라도,
크게 문제가 되지 않을 적정한 공간을 묶는 편이 낫고, 이 고민의 결과로 바이트라는 단위가 생겼습니다.

  • 1바이트는 256개 값 표현가능 1byte = 8bit

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

식별자와 변수

변수는 변할 수 있는 수 이고, 킴퓨터 용어로 쓸 때는 '변할 수 있는 무언가'라는 명사로 확정, '무언가'란 데이터를 말합니다.

식별자는 어떤 데이터를 식별하는데 사용하는 이름, 즉 변수명 입니다.

변수 선언과 데이터 할당

변수 선언

let a ;
변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a
이렇게 보면 변수란 결국 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇.

변수를 선언하면 컴퓨터는 메모리에서 비어있는 임의의 공간 하나를 확보합니다.
임의로 정한 공간의 이름(식별자)를 a 라고 지정!
=> 여기까지가 변수 선언과정
이후 사용자가 a에 접근하고자 하면 컴퓨터는 메모리에서 a라는 이름을 가진 주소를 검색해, 해당 공간에 담긴 데이터를 반환

데이터 할당

let a;
a = "abc"

let a = "abc"

실제로는 해당 위치에 문자열 "abc"를 직접 저장하지는 않습니다.
데이터를 저장하기 위한 별도의 메모리 공간을 다시 확보해서,
문자열 "abc"를 저장하고, 그 주소를 변수에 저장합니다.

메모리에서 변수 영역과 데이터 영역으로 나누고,
변수가 선언됐을 때, 변수 영역에서 빈 공간을 확보하고
확보한 공간의 식별자를 a로 지정하고(let = a)
데이터 영역의 빈공간에 문자열 "abc"를 지정 (a = "abc")
변수 영역에서 a라는 식별자를 검색한다.
앞서 저장한 문자열 주소를 변수영역에 확보한 공간에 대입
-> 왜 대입을 할까요? 변수영역에 값을 직접 대입하지 않고,
굳이 한단계를 더 거칠까요 ? 이는 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위한 고민의 결과입니다.

만약 확보된 공간 내에서만 데이터 변환을 할 수 있다면, 변환한 데이터를 다시 저장하기 위해서는 "확보된 공간을 변환된 데이터 크기에 맞게 늘리는 작업이 선행 되어야 함"

해당 공간이 메모리 상의 가장 마지막에 있었다면, 뒤쪽으로, 늘리기만 하면되서 상관없지만 중간에 있는 데이터를 늘려야 하는 상황이라면? 해당 공간보다 뒤에 저장된 데이터들을 전부 뒤로 옮기고, 이동시킨 주소를 각 식별자에 다시 연결하는 작업 필수입니다.
=> 결국 효율적으로 문자열 데이터의 변환을 처리하려면, 변수와 데이터를 별도의 공간에 나누어 저장하는게 최적입니다.

let a = 10
a = 100

식별자 a에 값을 재할당 하면 원래 주소의 값이 변하는게 아니라 100이라는 숫자를 새로 만들어 별도의 공간에 저장하고 그 주소를 변수 공간에 연결
=> 기존 문자열에 어떤 변환을 가하든 상관없이 무조건 새로 만들어 별도 공간에 저장!

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

불변 값.

"변수"와 "상수"를 구분하는 성질은 "변경 가능성"
바꿀 수 있으면 "변수", 바꿀 수 없다면 "상수"
불변값과 상수를 같은 개념으로 오해하기 쉽지만

불변값 !== 상수 이니 꼭 기억하자

  • 변수와 상수를 구분짓는 변경 가능성의 대상은 "변수 영역" 메모리
    -> 한 번 데이터 할당이 이루어진 변수 공간에 다른 데이터를 재할당 가능한지 여부가 제일 큰 관건
  • 불변성 여부를 구분 할 때의 변경 가능성의 대상은 "데이터 영역" 메모리
    -> 문자열 값도 한 번 만든 값을 바꿀 수 없고, 숫자 값도 다른 값으로 변경 할 수 없다. 변경은 새로 만드는 동작을 통해서만 이뤄집니다.
    이것이 불변성의 성질!
    한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않습니다.

가변 값

참조형 데이터는 모두 가변 값일 것 같은 느낌이 듭니다.
기본적인 성질은 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고, 아예 불변값으로 활용하는 방안도 있습니다.

기본형 데이터와의 차이는 "객체의 변수(프로퍼티)영역이 별도로 존재한다는 점" 입니다.
객체가 별도로 할애한 영역은 변수 영역일 뿐 "데이터 영역"은 기존의 메모리 공간을 그대로 활용하고 있습니다. 데이터 영역에 저장된 값을 모두 불변값입니다.
그러나 변수에는 다른 값을 얼마든지 대입할 수 있습니다.
이 부분 때문에 흔이 참조형 데이터는 불변하지않다(가변 값이다)라고 하는 것이죠

  • 참조 카운트가 0인 메모리 주소는 가비지 컬렉터의 수거 대상이 됩니다.
    가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모라 사용량이 포화 상태에 임박할 때마다 자동으로 수거 대상들을 수거합니다. 수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈공간이됩니다.

변수 복사 비교

let a = 10;
let b = a;

const obj1 = { c:10, d:'ddd' }
const obj2 = obj1

a !== b
obj1 === obj2

이 결과가 바로 기본형과 참조형 데이터의 가장 큰 차이 입니다.
사실은 어떤 데이터 타입이던 간에 변수에 할당하기 위해서는 주소 값을 복사 해야 합니다.
엄밀히 따지면, 자바스크립트의 모든 데이터 타입은 참조형 데이터
다만, 기본형은 주솟값을 복사하는 과정이 한 번만 일어나고,
참조형은 한 번 더 거치게 된다는 차이

객체 자체를 변경했을 때,

let a = 10;
let b = a;

const obj1 = { c:10, d: 'ddd'}
const obj2 = obj1

b = 15;
obj2 = { c:20, d: 'ddd' }

obj2에도 새로운 객체를 할당 함으로써 값을 직접 변경하였습니다.
이제 메모리의 데이터 영역의 새로운 공간에 새 객체가 저장되고,
그 주소를 변수 영역의 obj2 위치에 저장 => 객체에 대한 변경임에도 값이 달라졌다.
즉, 참조형 데이터가 '가변 값'이라고 설명할 때 '가변'은 첨조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때만 성립됩니다.

불변 객체

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

데이터 자체를 변경하고자 하면(새로운 데이터를 할당하고자 하면) 기본형 데이터와 마찬가지로 기존 데이터는 변하지 않는다.
그렇다면, 내부 프로퍼티를 변경할 필요가 있을 때마다 매번 새로운 객체를 만들어 재할당 하기로 구칙을 정하거나 자동으로 새로운 객체를 만드는 도구를 활용한다면, 객체 역시 불변성을 확보합니다.

그럼 어떤 상황에서 불변 객체가 필요할까요 ? 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 종종 발생하는데 바로 이럴 때 불변 객체가 필요합니다.

얕은 복사와 깊은 복사

얕은 보사는 바로 아래 단계의 값만 복사하는 방법이고,
깊은 복사는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법입니다.

얕은 복사를 수행했다는 말은 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사한다는 의미, 그러면, 해당 프로퍼티에 대해 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가리키게 됩니다.
=> 사본을 바꾸면 원본도 바뀌고, 원본을 바꾸면, 사본도 바뀝니다.
쉽게 말해서, 얕은 복사는 데이터 주소만 복사해오는 것이고, 깊은 복사는 아예 새로운 객체안에 속성(Property)를 복사하는 것
그러니까 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서
완전히 새로운 데이터를 만들고자 할 때, 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우 그대로 복사하면 되지만, 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야함!

객체를 복사한 다음 원본과 사본이 완전이 다른 객체를 참조하게 되어 어느쪽의 프로퍼티를 변경하더라도 더룬 쪽에 영향을 주지 않는다.

Undefined and Null ..

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

Undefined 와 Null

두 값의 의미는 같은 거 같지만 미세하게 다르고 사용하는 목적도 다릅니다.
Undefined는 사용자가 명시적으로 지정할 수도 있지만, 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여하는 경우가 있습니다.
자바스크립트 엔진은 사용자가 응당 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로는 그렇게 하지 않았을 때 Undefined를 반환합니다.
다음 세 가지 경우가 해당됩니다.

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

배열의 경우 조금 특이한 동작을 하는데

const arr1 = [];
arr.length = 3
console.log(arr) = [empty x 3]

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

const arr3 = [Undefined,Undefined,Undefined]
console.log(arr3) = [Undefined,Undefined,Undefined]

1,2 번은 배열의 3개의 빈 요소를 확보했지만 확보된 각 요소에서 문자 그대로 어떤 값도 심지어 Undefined도 할당돼 있지 않다를 의미,
이 처럼 '비어있는 요소'와 'Undefined를 할당한 요소'는 출력 결과부터 다릅니다. '비어있는 요소'는 순회와 관련된 많은 배열 메서드들의 순회 대상에서 제외됩니다.

사용자가 지정한 Undefined는 그 자체로 값이다. 비록 '비어있음'을 의미,
값 처럼 사용 가능하고 자바스크립트 엔진이 반환해주는 Undefined는 해당 프로퍼티 내지 배열의 키 값(index) 자체가 존재하지 않음을 의미 이렇게 되면 혼란을 야기하므로 혼란을 피하기 위해 직접적으로 Undefined 할당하지 않고 사용, "비어있음"을 명시적으로 나타내고 싶을 때는 Null을 쓰면 됩니다.
null은 이런 용도로 만든 데이터 타입입니다.
한가지 주의할 점이 있다면, typeof null 은 object입니다.
null인지 Undefined인지 구분하려면 일치 연산자(===)로 확인해야 알 수 있습니다.

총 정리

자바스크립트 데이터 타입은 크게 기본형과 참조형이있다.
기본적으로 기본형은 불변 값, 참조형은 가변값이다.

변수는 변경 가능한 데이터가 담길 수 있는 공간이고, 식별자는 그 변수의 이름을 말함

변수를 선언하면 컴퓨터는 우선 메모리의 빈 공간에 식별자를 저장, 그 공간에 자동으로 Undefined를 할당 이후 그 변수에 기본형 데이터를 할당하려고 하면 별도의 데이터 공간에 데이터를 저장하고 그공간의 주소를 변수의 값 영역에 할당합니다.

참조형 데이터를 할당하고자 할 때는 컴퓨터는 참조형 데이터 내부프로퍼티들을 위한 변수 영역을 별도로 확보해서 확보된 주소를 변수에 연결하고 다시 앞서 확보한 변수 영역에 각 프로퍼티의 식별자를 저장하고, 각 데이터를 별도의 공간에 저장해서 그 주소를 식별자들과 매칭시킵니다. 이 처럼 할당 과정에서 기본형과 차이가 생긴 이유는 참조형 데이터가 여러개의 프로퍼티(변수)를 모은 "그룹" 이기 때문입니다. 그리고 이 차이로 인해 참조형 데이터를 '가변 값'으로 여겨야만 하는 상황이 발생합니다.

참조형 데이터를 가변값으로 여겨야 하는 상황에서도 불변값으로 사용하는 방법이 있는데 이 경우 내부 프로퍼티들을 일일이 복사하면 됩니다(깊은 복사) 혹은 라이브러리를 사용하는 방법도 있습니다.

"없음"을 나타내는 값은 두 가지인데 Undefined 와 null이고
Undefined는 어떤 변수에 값이 존재하지 않을 경우를 의미하고
null은 사용자가 명시적으로 '없음'을 표현하기 위해 대입한 값입니다.
본래의 의미에 따라 사용자가 없을을 표현하기 위해 명시적으로 Undefined 대입하는 것은 '지양'하는 것이 좋겠습니다.

profile
헤더부터 푸터까지!!!

0개의 댓글