본문 바로가기
👩‍💻 Programming/JavaScript

코어 자바스크립트_1장 데이터 타입

by codingBear 2022. 10. 24.
728x90
반응형

01. 데이터 타입의 종류

👉 이번 장의 학습 목표는 기본형 타입과 참조형 타입이 서로 다르게 동작하는 이유를 알고 적절히 활용하는 것이다.

 

❔ 기본형과 참조형을 구분하는 기준

  • 할당이나 연산 시
    • 기본형: 주솟값을 바로 복제
    • 참조형: 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제

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

1-2-1. 메모리와 데이터

  • 비트(bit): 0 또는 1만 표현할 수 있는 하나의 메모리 조각.
  • 식별자(identifier): 각 비트는 고유한 식별자를 통해 위치를 확인.
  • 바이트(byte): 1바이트 = 8비트. 자주 사용하지 않는 데이터를 검색 시간 단축을 위해 적정한 공간에다 놔둔 비트의 묶음.

👉 C/C++, Java 등 정적 타입 언어는 메모리 낭비를 최소화하기 위해 데이터 타입별로 할당할 메모리 영역을 2바이트, 4바이트 등으로 나눔. 따라서 2바이트 크기의 정수형 타입(short)을 4바이트 크기의 정수형 타입(int)로 바꾸려면 '형변환'을 거쳐야 해서 매우 번거로움. 메모리 환경이 넉넉해진 상황에서 등장한 JavaScript는 숫자의 경우 정수형, 부동소수형 구분 없이 8바이트(64비트)를 확보.

(🔸 1비트: 부호(+/-), 11비트: 지수부, 52비트: 가수부)

👉 모든 데이터는 바이트 단위의 식별자 ,즉 메모리 주솟값(memory address)를 통해 서로 구분하고 연결.

 

1-2-2. 식별자와 변수

❔ 변수

👉 변할 수 있는 '데이터'. 식별자 = 변수명


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

1-3-1. 변수 선언

 

1-3-2. 데이터 할당

👉 데이터 할당은 식별자 주소에 값을 직접 저장하는 방식이 아니라 별도의 메모리 공간에 데이터를 저장한 뒤 그 주소를 변수의 값에 저장하는 식으로 이뤄짐.

❔ 변수의 값에 직접 데이터를 저장하지 않는 이유

👉 자유로운 데이터 변환, 효율적인 메모리 관리

👉 기존 할당된 데이터를 수정/변경하려고 하면 컴퓨터는 무조건 새로운 데이터를 만들어 별도의 공간에 저장. 만약 변수 500개를 생성하여 숫자 5를 할당한다고 하면 일일이 숫자 5를 500군데 할당하는 것보단 한 곳에 숫자 5를 저장해놓고 해당 주소를 할당하는 편이 훨씬 효율적이다.

🔸 기존 데이터가 아무 변수에도 할당되지 않을 경우 가비지 컬렉터(garbage collector)의 수거대상이 됨


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

1-4-1. 불변값

👉 기본형 데이터는 모두 불변값

👉 변수와 상수를 구분하는 성질은 '변경 가능성'. 변경 가능성의 대상은 변수 영역 메모리. 다른 데이터로 재할당할 수 있는지가 관건.

👉 불변성의 변경 가능성 대상은데이터 영역 메모리. 한번 만들어진 데이터는 가비지 컬렉팅을 당하지 않는 한 영원히 변경되지 않음.

👉 위 예제에서 변수 a에 각각 할당된 문자열 'abc'와 'abcdef'는 별개의 데이터

👉 5번째 줄에서 변수 c에 숫자 5를 할당할 때 4번째 줄에서 만든 숫자 5를 재활용

👉 6번째 줄에서 변수 b에 7을 재할당할 때 기존의 숫자 5를 숫자 7로 변경하는 게 아니라 데이터 영역에 숫자 7이 있는지 찾아서 있다면 재활용, 없다면 새로 만들어 그 주솟값을 변수 b의 값으로 할당

 

1-4-2. 가변값

👉 기본형 데이터와 차이는 객체의 변수(프로퍼티) 영역이 따로 존재한다는 점.

👉 데이터 영역에 저장된 값은 모두 불변값이나 변수에는 다른 값을 얼마든지 대입 가능. 따라서 참조형 데이터는 가변(mutable)값이라고 일컫는 것임.

 

👉 변수 obj1의 값에 할당된 주솟값은 @5001로 변하지 않음. 새로운 데이터 2를 객체 @5001의 변수 영역 값에 재할당한 것임. 즉 새로운 객체가 만들어진 것이 아니라 기존 객체 내부의 값만 바뀜.

 

👉 참조형 데이터의 프로퍼티에 다시 참조형 데이터를 할당하는 경우를 중첩 객체(nested object)라고 함.

 

🔷 obj.arr[1] 검색 과정

 

❔ 여기서 다음과 같이 재할당 명령을 내린다면

👉 새로운 주소에 문자열 'str'을 저장하고 그 주소를 프로퍼티 arr의 값에 할당. 기존 데이터였던 @5003은 참조 카운트가 0이 되어 가비지 컬렉터의 수거대상이 되고 @8104 ~ ?라는 값이 삭제됨.

 

1-4-3. 변수 복사 비교

🔷 변수 복사할 때 기본형 데이터와 참조형 데이터의 차이

👉 변수를 복사하는 과정에서 기본형과 참조형 모두 복사된 변수가 기존 변수의 데이터와 같은 주솟값을 바라본다는 건 같으나 데이터 할당 과정에서 차이가 있어 복사 이후 동작이 다름.

 

👉 변수 복사 결과 기본형 a와 b는 서로 다른 주소를 바라보나, 참조형 obj1과 obj2는 여전히 같은 주소를 바라봄.

👉 자바스크립트에서 변수에 데이터를 할당하려면 주솟값을 복사하기 때문에 엄밀히 따지면 모든 데이터 타입은 참조형. 다만 기본형은 주솟값 복사를 한 번만 하고, 참조형한 단계 더 거친다.

 

🔷 객체 자체를 변경했을 때

👉 객체에 새로운 객체를 할당하여 값을 직접 변경하면 메모리 데이터 영역에 새로운 객체가 저장되고 그 주소를 기존 객체의 값으로 할당함. 즉, 참조형 데이터가 가변값이라는 것은 내부의 프로퍼티를 변경할 때만 성립.

🤔 위의 표를 보면 알 수 있듯, 객체 자체를 변경할 때는 기존의 프로퍼티에 새로운 데이터를 재할당하는 것이 아니라, 완전히 새로운 객체를 생성하여 그 주솟값을 할당함. 따라서 기존의 프로퍼티가 새로운 프로퍼티로 대체됨. 프로퍼티의 값을 바꿀 때는 프로퍼티의 값에 새로운 데이터를 재할당함. 즉 기존의 프로퍼티가변(mutable)한 것임.


05. 불변 객체

1-5-1. 불변 객체를 만드는 간단한 방법

❔ 불변 객체가 필요한 경우

👉 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우

👉 user2는 user의 객체 주솟값을 할당한 것임. 따라서 user와 user2는 같은 객체를 바라봄. 이 상황에서 그 객체의 프로퍼티를 Jung으로 바꾸었기 때문에 결과적으로 원본 객체의 값이 변경됨.

 

🔷 변경 전과 후, 서로 다른 객체를 바라보게 만들기

👉 함수 changeName이 기존의 프로퍼티를 변경하는 것이 아닌, 새로운 객체를 반환하도록 수정되었다는 점에 주목하자. 허나 필요한 프로퍼티를 하드코딩한 코드이다. 원본 객체의 프로퍼티 개수에 상관 없이 원본 객체의 모든 프로퍼티를 복사하여 새로운 객체를 반환하도록 리팩토링해보자.

👉 이렇게 코드를 수정하여 협업하는 팀원들이 user 객체 내부를 변경할 때는 무조건 copyObject 함수를 사용하기로 하고 규칙을 지킨다는 전제 하에서는 원본 객체 user는 불변 객체가 된다.

🔸 이렇게 규칙을 정하는 것보다는 immutable.js, baobab.js 등의 라이브러리로 프로퍼티를 변경할 수 없게끔 제약을 거는 편이 안전함.

 

1-5-2. 얕은 복사와 깊은 복사

얕은 복사(shallow copy): 바로 아래 단계의 값만 복사
깊은 복사(deep copy): 내부 값들을 전부 복사

👉 위 예제의 copyObject 함수는 얕은 복사만 수행. 이 말은 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주솟값만 복사한다는 뜻. 원본과 사본 모두 동일한 참조형 데이터의 주소를 가리키므로 사본을 바꾸면 원본이, 원본을 바꾸면 사본이 바뀜.

 

👉 11번째 줄에서 사본인 user2의 프로퍼티 name을 바꿔도 원본 user의 프로퍼티는 바뀌지 않았다. 따라서 동등한지 비교하면 false를 반환. 반면 14번째 줄과 17번째 줄에서는 원본과 사본 중 한쪽의 값을 바꿀 경우 반대쪽의 값도 함께 바뀜. 

👉 즉 객체의 바로 아래 단계의 프로퍼티에 대해서는 완전히 새로운 데이터가 할당되었으나 중첩 객체인 프로퍼티기존

데이터를 그대로 참조.

👉 따라서 중첩 객체인 프로퍼티를 깊은 복사를 통해 불변 객체로 만들어야 함.

👉 2번째 줄에서 프로퍼티의 내부까지 복사해서 새로운 데이터를 생성하였다. 따라서 5번째 줄과 8번째 줄에서 원본과 사본을 비교하면 false를 반환함.

 

🎯 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 한다면
기본형 데이터: 그대로 복사
참조형 데이터: 내부의 프로퍼티 복사

 

🔷 객체 내부의 모든 프로퍼티를 깊은 복사하는 재귀 함수

 

🔷 JSON을 활용한 깊은 복사

👉 객체를 JSON 문법으로 표현된 문자열로 전환했다가 다시 JSON 객체로 전환하면 깊은 복사됨.다만 숨겨진 프로퍼티 __proto__, getter/setter 등 JSON으로 변경할 수 없는 프로퍼티 모두 무시됨.(위 예제의 경우 func1, func2 등 함수) httpRequest로 받은 데이터를 저장한 객체 등을 복사할 때 용이.


06. undefined와 null

undefined

👉 어떤 값을 지정할 것이라고 예상되는 상황임에도 지정하지 않았을 때 반환됨.

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

👉 1의 경우 배열이라면 조금 특이하게 동작함.

👉 arr1과 arr2처럼 배열의 길이는 설정했으나 값을 할당하지 않은 경우 empty가 들어감. empty는 순회 대상에서 제외됨.

 

👉 위와 같은 결과는 배열도 객체임을 안다면 쉽게 이해 가능. length 프로퍼티만큼 무조건 빈 공간을 확보하여 각 공간마다 인덱스를 이름으로 지정하는 게 아니라, 객체와 마찬가지로 특정 인덱스에 값을 지정할 때 비로소 빈 공간을 확보하여 인덱스를 이름으로 지정하고 데이터의 주솟값을 저장함. 즉, 값이 지정되지 않은 인덱스는 '아직 존재하지 않는 프로퍼티'임.

 

👁‍🗨 더 보기
어딘가에 값으로 할당된 undefined는 실존하는 데이터.
자바스크립트 엔진이 자동으로 반환하는 undefined는 값이 없음을 나타냄.

'변수 선언 시 자동으로 undefined를 할당'하는 것이 아니라, 그렇게 아무 것도 할당하지 않은 변수에 접근할 때 비로소 undefined가 할당되는 것임.

 

null

👉 '비어 있음'을 명시적으로 나타내고 싶을 땐 null을 쓰면 됨. 다만 typeof로 체크 시 object를 반환한다는 점에 주의.(자바스크립트 자체 버그)

 


07. 정리

👉 기본형: 불변값, 참조형: 가변값
👉 변수를 선언 -> 메모리 빈 공간에 식별자 저장 -> 공간의 값에 undefined 할당됨
❔ 기본형 데이터를 할당 시
별도 공간에 데이터 저장 -> 별도 공간의 주소를 변수의 값 영역에 할당
❔ 참조형 데이터 할당 시
내부 프로퍼티들을 위한 변수 영역 확보 -> 확보한 변수 영역 주소 변수에 연결 -> 앞서 확보한 변수 영역에 프로퍼티 식별자 저장 -> 별도 공간에 저장된 데이터를 식별자들과 매칭
👉 참조형 데이터는 여러 개의 프로퍼티(변수)로 된 그룹. 따라서 참조형 데이터를 '가변값'으로 여겨야 하는 상황이 생김
👉 참조형 데이터를 불변값으로 사용하는 방법: 깊은 복사, 라이브러리
👉 명시적으로 없음을 나타낼 때는 'null' 사용

함께 보기

가비지 컬렉션

 

Garbage collection

 

javascript.info

 

728x90
반응형

댓글