js / 원시/참조(객체) 값에 관한 내용

Duboo·2023년 9월 13일
0

자바스크립트

목록 보기
4/7
post-thumbnail

JS에서 데이터 타입을 크게 2가지로 구분할 수 있습니다.


원시 값(Primitive Type)

단순한 데이터로 모든 원시 값은 변경이 불가능

한번 생성된 원시 값은 읽기 전용으로 변경할 수 없습니다.
원시 값을 변수에 할당하면 변수에 실제 값이 저장됩니다.

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • Symbol
  • Bigint

프로그램이 실행될 때 메모리의 4가지 영역(코드, 데이터, 힙, 스택)으로 구분되어 데이터를 저장하고 처리하게되는데, 이때 원시 값들은 스택 영역에 존재하게 됩니다.


변경 불가능한 값에 대한 의미

원시 값을 할당한 변수는 원시 값 자체를 값으로 가집니다.
변경이 불가능한 값이란 의미는 변수에 재할당이 불가능하다는 의미가 아닌,
메모리에 올라간 값이 변경되지 않는다는 의미입니다. 해당 내용은 아래에서 다시 살펴봅니다.

let num = 88;
num = 99;

위와 같이 원시 값(88)을 할당 받은 변수 num에 새로운 값(99)을 재할당하면 초기화했던 88이 저장된 메모리 안의 원시 값 자체를 수정하는 것이 아닌, 새로운 메모리 공간에 재할당한 원시 값을 저장하여 num의 메모리 주소는 재할당한 원시 값인 99가 저장된 주소로 바뀌게 됩니다.


다른 케이스로 보자면

먼저 name 변수에 toUpperCase()를 사용해서 대문자로 값을 변경했지만 name 변수의 값 자체는 변하지 않았습니다.

또한 이미 선언되어 있는 변수 color에 새로운 원시 값(blue)을 재할당하는 경우 자바스크립트는 새로운 메모리 공간에 새로 할당되는 값을 복사해 입력하고 기존에 사용하던 변수명color이 이를 할당하여 사용하게 합니다.

새로운 변수 copy에 기존에 있던 변수color를 할당하는 경우 새로운 변수copy가 새로운 메모리 공간에 할당되고 해당 위치에 기존 변수color에 할당되어 있던 값blue을 그대로 복사합니다.


이는 원시 값이 가지고 있는 불변성(immutability) 특징으로 메모리에 저장되어 있는 값 자체를 변경하는 것이 불가능하기에 값을 변경, 재할당하는 경우 현재 위치한 메모리 주소에 저장되어 있는 값을 변경하는 것이 아닌, 다른 메모리 영역에 저장하고 그 위치를 참조하게 되며, 이전 값과 현재 값 모두 메모리상에 존재하게 됩니다.

더 이상 사용되지 않는 값은 아무런 변수도 사용하지 않기에 즉, 참조 카운트가 0이기 때문에 가비지 컬렉터에 쌓이게 되고 결국엔 제거되게 됩니다.

다시 위의 내용을 정리하자면

  • 메모리에 선언한 값을 고정 크기로 저장
  • 저장된 값을 변수가 직접적으로 가르키는 형태
let dog = 'cute';
let cat = 'cute';

console.log(dog === cat); // true

let puppy = dog;
console.log(dog === puppy); // true

따라서 값 자체를 비교하기 때문에 위와 같이 다른 변수명에 저장되어 있어도 혹은 복제된 값이어도 같다는 결과가 나옵니다.


참조 값(Reference Type)

JS에서 원시 값을 제외한 나머지는 모두 참조 값입니다.

  • Object (객체)
  • Array (배열)
  • Function (함수)

참조 값의 특징은 원시 값과 다릅니다.

  • 별도의 메모리 공간에 저장
  • 변수에 할당 시 데이터에 대한 주소(메모리 주소)가 저장
  • 자바스크립트 엔진은 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근

메모리에 선언한 값을 고정 크기로 저장하는 원시 값과의 가장 큰 차이는 크기가 동적으로 변할 수 있다는 것입니다.

때문에 원시 값과 참조 값을 관리하는 방식이 다릅니다.

메모리 구조 공간 하나에는 하나의 값만 들어갈 수 있습니다.

하지만 위에 객체는 name = "kim", age = 10 각 2개의 프로퍼티와 값을 가지고 있습니다.

자바스크립트에서 객체를 생성하게 되면 어느정도의 공간을 차지하는지 모르기 때문에 메모리 영역에 위 그림처럼 ex) 5002 ~ ???? 까지의 공간을 확보를 합니다.

힙 메모리에 객체 인스턴스를 생성하고, 해당 인스턴스가 존재하는 위치를 스택 메모리에 기록하여 사용합니다. - 힙 메모리에 저장되어 있는 주소를 스택 영역에 저장함


완전히 같은 내용의 객체를 선언하는 경우

앞서 설명한 내용대로 객체를 생성하게 되면 어느정도 공간을 확보한 후 힙 메모리에 저장하고 스택 메모리에 힙 영역의 주소를 기록합니다.

위 그림에서 알 수 있듯이 완전히 같은 내용을 가진 객체이지만 다른 주소를 가지고 또한 다른 영역에 저장되게 됩니다.

console.log(user === user2); // false

위 콘솔의 결과처럼 false가 나오는 이유는 참조 값의 비교는 힙 영역에 저장된 메모리 주소를 비교하기 때문입니다.

결과적으로 똑같은 값처럼 보일 순 있지만 자바스크립트가 인식하는 힙 영역의 주소는 다르기 때문입니다.

결과적으로 객체를 할당한 변수 user와 user2의 실제 객체의 값은 힙 메모리 영역에 존재하며, 변수가 가지는 값은 스택 메모리 영역에 있는 실제 값을 참조하는 힙 메모리 주소를 값으로 가지게 됩니다.

즉, 참조 값은 생성된 객체가 저장된 힙 메모리 공간의 주소를 의미합니다.


객체를 복사하는 경우

새로운 변수에 기존에 존재하는 객체를 할당하는 경우 변수명은 다르지만 힙 영역의 주소를 복사하게 됩니다. 즉, 동일한 객체를 참조하게 됩니다.

console.log(user === user3); // true

따라서 변수 user 와 user3은 일치한다는 결과가 나옵니다.

user.name = "yoon";

console.log("user1 : ", user1);
console.log("user3 : ", user3);
//user1 :  {name: 'yoon', age: 10}
//user3 :  {name: 'yoon', age: 10}

위 처럼 같은 객체를 사용하기 때문에 하나의 객체만 변경되어도 동일한 힙 영역의 객체를 사용하기 때문에 복사한 값까지 변경됩니다.


때문에 객체의 실제 값만 복사를 하고 싶다면 다른 방법을 사용해야합니다.
다음은 깊은 복사와 얕은 복사를 알아보겠습니다.

profile
둡둡

0개의 댓글