프로그래밍 공부하기

불변성과 가변성 1 - JS의 자료형 본문

Web/[JS] Common

불변성과 가변성 1 - JS의 자료형

ihl 2021. 1. 7. 18:25

JavaScript의 자료형 분류

  JavaScript의 자료형은 크게 Primitive Type(원시타입)과 Refefence Type(참조 타입)으로 나뉜다.  Primitive type은 할당이나 연산 시 값이 복제되고 Reference type은 참조된다. 또한 Primitive type은 불변값(immutable) 이며 Referenct type은 가변값(mutable)이라고 알려져있다. 이를 구제척으로 알아보자.

 

 

1. Primitive Type

 1) 선언과 할당

  Primitive type을 선언하고 값을 할당하면 메모리(식별자)에 값(숫자, 문자열 등)을 저장하게 되며 변수를 사용하거나 다른 변수에 할당할 때 메모리 안에 있는 저장된 값을 사용하게 된다고 배운다. 그러나 엄밀히 말하면 primitive type 또한 주소 값을 갖고있으며 primitive type의 값을 변경하면 주소 값이 변경된다. 다음 코드를 살펴보자

let a;  //변수 a 선언
a = 77;  //변수 a에 77 할당

  위 코드에서 프로그래머는 변수 a를 선언하고 a에 1을 할당하였다. 이 코드 실행하면 메모리에서는 다음과 같은 일이 발생한다.

let a = 77

    • 메모리에서 빈 공간을 확보한다.(주소 101)
    • 빈 공간의 식별자를 a라 정한다.
    • 데이터 중 77이 이미 저장된 공간을 찾고 없으면 새로운 공간에 77을 저장한다.(주소 301)
    • a에 3에서 저장한 데이터 공간의 주소를 대입한다.

  왜 a에 바로 77을 저장하지 않고 주소를 저장하는 것일까? 이는 메모리를 효율적으로 사용하기 위함이다. 새로운 변수를 선언하여 똑같이 77이라는 값을 할당해보자.

let b = 77;

let b = 77

  1. 메모리에서 빈 공간을 확보한다.(주소 102)
  2. 빈 공간의 식별자를 b라 정한다.
  3. 데이터 중 77이 이미 저장된 공간이 있으므로 b에 해당 주소를 대입한다.

  만약 a,b에 바로 77을 저장했다면 메모리에 77을 두 번 저장해야한다. 이보다는 77을 한 번만 저장하고 a와 b에 77이 저장된 주소를 가리키게하는 것이 효율적일 것이다. 또한 primitive type 중 string의 경우 크기가 가변적이기 때문에 만약 string 값이 데이터 공간보다 커지게 된다면 다음 주소에 있는 식별자와 식별자의 값을 그 만큼 뒤쪽으로 shift해줘야할 것이다. 이러한 이유 때문에 식별자 공간에 데이터를 바로 저장하지 않고 별도의 공간에 저장하며 식별자는 주소값을 갖고 있는 것이다.

 

  2) 불변성

  primitive type은 불변값이다. 왜 불변값인지 다음의 예시를 통해 알아보자

let a = 77;
let b = 77;
b = b+11; //88

b=88

  1. 메모리에서 빈 공간을 확보한다.(주소 101)
  2. 빈 공간의 식별자를 a라 정한다.
  3. 데이터 중 77이 이미 저장된 공간을 찾고 없으면 새로운 공간에 77을 저장한다.(주소 301)
  4. a에 iii에서 저장한 데이터 공간의 주소를 대입한다.
  5. 메모리에서 빈 공간을 확보한다.(주소102)
  6. 빈 공간의 식별자를 b라 정한다.
  7. 데이터 중 77이 이미 저장된 공간이 있으므로 b에 해당 주소를 대입한다.
  8. 데이터 중 88이 이미 저장된 공간을 찾고 없으므로 새로운 공간에 88을 저장한다.
  9. b에 8에서 저장한 데이터 공간의 주소를 대입한다.

  위와 같이 b의 값을 변경하면 새로운 공간에 88이 할당되고 b는 새로운 공간의 주소를 갖게된다. 기존에 있던 77이란 값(Number)은 변하지 않는 것이다. 즉, primitive type은 한 번 만든 값을 변경하지 않는다.(메모리 상에 고정된 크기와 값으로 저장) 이것이 primitive type의 불변성이다. 

 

  만약 a의 값도 다른 값으로 변경하면 어떻게 될까? a를 다른 값으로 변경한다면 77을 가리키는 식별자가 하나도 없는 상황(@301의 참조 카운트 값이 0)이 된다. 이러한 경우 77이 담긴 메모리는 가비지 컬렉팅에 의해 처리된다.

 

2. Reference Type

 1) 선언과 할당

  Reference Type을 선언하고 값을 할당하면 식별자에는 주소가 저장되고 내용물은 Heap 영역에 저장된다. 변수를 사용할 때는 식별자 안에 있는 주소를 보고 해당 주소에 저장된(Heap 영역) 내용물을 참조한다고 배웠다. 그렇게 되면 위의 primitive와의 차이가 없다. 사실 primitive type이 1번의 주소를 통해 값에 접근한다면 reference type은 2번의 주소를 통해 값에 접근한다. 다음의 예시를 살펴보자.

let obj1 = {
  a: 77,
  b: 'hello'
}

obj1 = { a:77, b: 'hello; }

  1. 메모리에서 빈 공간을 확보한다.(주소 101)
  2. 빈 공간의 식별자를 obj1이라 정한다.
  3. obj1의 값을 저장할 공간(주소 301)을 할당한다.
  4. 저장해야하는 값이 데이터 그룹이므로 이들을 저장하기 위한 별도의 변수 영역(주소 501~)을 마련하고 그 영역의 주소를 저장한다.
  5. 마련된 영역에 a, b 라는 property 이름을 지정한다.
  6. 데이터 중 77이라는 값이 없으므로 이를 새로운 공간(주소 303)에 저장하고 이 주소를 obj1.a(501)에 저장한다.
  7. 데이터 중 'hello'라는 값이 없으므로 이를 새로운 공간(주소 304)에 저장하고 이 주소를 obj1.b(502)에 저장한다.

  primitive type과의 차이는 property영역이 따로 존재한다는 것 뿐이다. obj1란 식별자도 primitive 처럼 주소를 저장하고 있고, obj1.a와 obj1.b도 주소를 저장하고 있다. 단지 obj1의 내용물인 a,b 라는 property들을 주소로 한번 더 연결하고 있는 것 뿐이다.

 

  2) 가변성

  이번엔 obj1의 값을 변경하여 refrence type이 왜 가변값인지 알아보자.

let obj1 = {
  a: 77,
  b: 'hello'
}
obj1.a = 88;

obj1.a = 88

  obj1.a를 변경하는 것은 primitive type의 값을 변경하는 과정과 동일하다. 따라서 메모리는 위와 같은 결과가 된다. 이 때 obj1의 값을 살펴보면 primitive type이 바라보고 있는 값이 새로운 값의 주소로 변경된 것과 달리 obj1의 값은 @301 그대로이다. 그러나 obj1의 내용물인 obj1.a의 값이 @305로 변경되었다. 만약 obj1에 c라는 property가 추가된다면 @503이 c라는 이름으로 새로 할당되고 obj1의 내용으로 추가될 것이다. 즉, 객체의 property를 변경했을 때 새로운 객체가 생기는 것이 아니라 기존 객체의 값을 변경한다. 따라서 referenct type이 가변적인 것이다. 이러한 가변성 때문에 refrence type은 Heap이라는 영역에 따로 저장된다.

 

primitive type의 불변성과 refrence type의 가변성을 비교하면 다음과 같다.

 

 

Primitive type과 Reference type

  위 그림에서 노란색 박스 부분이 primitive type, refrence type 부분의 값이라고 말할 수 있는 부분이다. 이 값 부분이 primitive type에서는 변하지 않고 refrence type에서는 변하기 때문에 각각 불변값, 가변값인 것이다. 따라서 refrence type의 가변성은 refrence type 자체를 변경할 경우가 아니라 그 내부의 property를 변경할 때만 성립한다.(primitive type의 a와 b, refrence type의 obj1은 공간을 구분하기위한 이름인 식별자이다. 또한 refrence type의 @303, @304는 primitive type인 obj1.a의 값이다.)

 

 


참고 서적

 

코어 자바스크립트

자바스크립트의 근간을 이루는 핵심 이론들을 정확하게 이해하는 것을 목표로 합니다!최근 웹 개발 진영은 빠르게 발전하고 있으며, 그 중심에는 자바스크립트가 있다고 해도 결코 과언이 아닙

book.naver.com

 

 

<번역>자바스크립트의 메모리 모델

이 글은 Ethan Nam의 JavaScript’s Memory Model을 번역한 글입니다. 원문은 JavaScript’s Memory Model 에서 확인하실 수 있습니다. // 변수를 선언하고 초기화 var a = 5 let b = 'xy' const c = true //새로운 값을 할당

junwoo45.github.io

 

 

'Web > [JS] Common' 카테고리의 다른 글

undefined와 null  (0) 2021.01.08
불변성과 가변성 2 - let과 const  (0) 2021.01.07
재귀함수와 꼬리재귀함수  (0) 2021.01.05
?. 연산자(Optional Chaining)  (0) 2021.01.01
??(null 병합 연산자)  (0) 2021.01.01
Comments