♻️ 개발자로 재활용/🟢 JavaScript

원시 자료형 & 참조 자료형

BuleRatel 2022. 11. 7. 12:15

데이터를 저장하는 방식에 따른 분류로 원시 자료형(primitive data type)과 참조 자료형(refrerence data type)이 있다.

  • 원시 자료형 : 변수에 value값을 직접 지정한다. 고정된 저장 공간을 차지하는 데이터. (number, string, boolean 등)
  • 참조 자료형 : 변수에 데이터에 접근할 수 있는 주소reference를 지정한다. 대량의 데이터를 다루기에 적합한 타입. (array, object 등)

참조 자료형원시 자료형과 달리 저장 공간이 유동적으로 늘어난다. 배열과 객체, 함수가 담긴 저장 공간은 특별한 저장 공간을 사용하기 때문이다. 이런 특성들에 대해 알아보자.

 

 

 


1. 원시 자료형 (primitive data type)

메모리를 stack이라고 이름붙인 하나의 사물함이라 가정해 보자. 변수 let a = 1;을 선언했을 때, 컴퓨터는 사물함 한 칸에 변수 a라는 이름을 붙이고 그 안에 변수의 값 1을 넣는다. 마찬가지로 찾을 때도 이름표 a를 찾아 그 안에 든 값을 꺼내온다. 이 방식을 원시 자료형이라고 한다. 

원시 자료형은 모두 '하나'의 데이터를 담고 있다. 값 자체에 대한 변경은 불가능(immutable)하지만, 변수에 다른 데이터를 할당할 수는 있다. 때문에 원시 데이터에서 데이터를 복사할 경우, 데이터의 값까지 복사하기 때문에 기존 데이터에는 영향이 가지 않는다. 

"hello world!"
"hello codestates!"
// "hello world!" 와 "hello codestates!"는 모두 변경할 수 없는 고정된 값

let word = "hello world!"
word = "hello codestates!"
// 하지만, word라는 변수에 재할당을 하여 변수에 담긴 내용을 변경하는 것은 가능

const num1 = 123;
num1 = 123456789; // 에러 발생
// const 키워드로 선언 시, 재할당은 불가

원시 자료형으로는 string, number, bigint, boolean, undefined, symbol, (null) 등이 있다. 

 

 

 


2. 참조 자료형 (primitive data type)

앞서 원시 자료형은 하나의 이름마다 사물함의 칸을 지정해주고, 하나의 데이터를 담는다고 말했다. 하지만 객체나 배열처럼 한 이름에 여러 데이터가 담겨 있을 때도 한 칸씩 데이터를 부여해주면 이걸 찾는 것도, 관리하는 것도 복잡해진다. 그래서 사물함의 칸을 없애고, heap이라는 공간을 만들었다. 배열 let a = [4, 5, 6];을 선언했을 때, 컴퓨터는 사물함 한 칸에 a라는 이름을 붙이고 데이터는 heap이라는 공간에 저장한다. 그리고 사물함에는 데이터를 찾아올 주소를 넣어 이름과 데이터를 연결시켜준다. 이 방식을 참조 자료형이라고 한다.

 

참조 자료형은 데이터 자체가 아닌, 주소를 복사하기 때문에 복사한 데이터에서 원소를 변경한다면 원본 데이터에도 영향이 간다. 

let x = { foo: 3 }; 
// x라는 객체에 foo라는 key와 3이라는 value를 할당. 
실은 {foo: 3}으로 접근할 수 있는 '주소'를 할당.
let y = x; 
// 변수 y에 x를 할당. x의 값이 참조 자료형이기 때문에, 
x의 값 {foo: 3}으로 접근할 수 있는 '주소'를 할당.
y.foo = 2; 
// y에 담긴 foo값을 변경하면, 원본 데이터인 x의 foo 값도 변경됨

x.foo // {foo: 2}

원시 자료형이 아닌 데이터타입은 모두 참조 자료형이다. 대표적으로 array, object, function이 있다.

 

 

 


3. 문제 예시

다음 코드가 실행된 후, 콘솔에서 확인할 수 있는 값은 무엇일까?

console.log('Hello World' === 'Hello World');
console.log(3.14 === 3.14);
console.log([1,2,3] === [1,2,3]);
console.log({ foo: 'bar' } === { foo: 'bar' });

1번 'Hello World'의 데이터타입은 string이며, 2번 3.14는 number이다. 두 타입 모두 원시 자료형이며, 값과 값을 비교하기 때문에 두 코드는 true가 출력된다.

하지만 3번은 array, 4번은 object참조 자료형이다. 이때는 값과 값은 별도의 저장 공간에 존재하기 때문에 두 자료의 주소값을 비교하게 된다. 때문에 두 참조 자료형의 주소값은 다르며, 결과적으로 false가 출력된다.

 

 다음 코드가 실행된 후, myArray의 값은 무엇일까?

let myArray = [2, 3, 4, 5];
let ourArray = myArray;
ourArray[2] = 25;
ourArray = undefined;
  • let myArray = [2, 3, 4, 5];
    우선 변수 myArray는 [2, 3, 4, 5]라는 배열 데이터타입이 할당되었다.
  • let ourArray = myArray;
    변수 ourArray에는 myArray의 주소값이 할당되었다.
  • ourArray[2] = 25;
    ourArray 주소값에 위치한 배열의 2번째 index 요소를 25로 변경했다. ourArray와 myArray의 주소값은 같으므로, 같은 데이터를 참조한다. 때문에 이 데이터는 [2, 3, 25, 5]로 변경되며, myArray도 [2, 3, 25, 5]으로 변경된다.
  • ourArray = undefined;
    변수 ourArray에 새롭게 할당된 undefined는 원시 자료형이다. 때문에 myArray에는 접근할 수 없고, myArray는 위에서 변경된 그대로인 [2, 3, 25, 5]를 유지한다.