[JavaScipt] 원시 타입, 참조 타입의 차이

김방울·2024년 8월 10일
0

JavaScript

목록 보기
7/7
post-thumbnail

최근 면접을 진행하다 원시 타입과 객체(참조) 타입의 메모리 저장 방식에 대한 차이에 대해 질문을 받아, 공부를 위해 내용을 정리해 보았습니다.🥲

원시 타입(primitive)

  • 객체가 아니면서 메서드 또는 속성도 가지지 않는 데이터
  • string, number, bigint, boolean, undefined, null, symbol 의 7가지 종류가 있음.
  • var,const 등으로 데이터 선언 시 스택에 저장되며, 변수 선언 시 사용한 변수 이름으로 데이터를 식별할 수 있다.

String과 Number 속성은 메서드가 있는데요?🙋

원시 값에는 메서드가 없지만 마치 메서드가 있는 것처럼 동작합니다. 원시 값에서 속성에 접근하려면, JavaScript는 값을 래퍼 객체로 "자동으로 포장"하고 대신 해당 객체 속성에 접근합니다. 예를 들어, "foo".includes("f")는 암시적으로 String 래퍼 객체를 생성하고 해당 객체에 대해 String.prototype.includes()를 호출합니다.

JavaScript를 실행될 때, 기본 문자열을 문자열 객체로 변환하므로 문자열 객체 메서드를 사용할 수 있습니다.

예를 들어 "cat".replace() 라는 구문이 있으면 인터프리터에서 "cat" 을 해석할 때 var str = new String("cat") 과 같은 객체 형식으로 변환하여 해석한다고 합니다. 🤔

참조 타입(reference)

  • 원시 타입에 속하지 않은 나머지 타입들
  • array, object, function
  • 그 외 date, collection 등등
  • 변수를 생성하고 참조 데이터 값을 할당하면 스택에 포인터가 저장되고, 데이터 자체는 힙 메모리에 저장된다.

스택, 힙 메모리가 무엇인가요?🙋

자바스크립트 엔진은 Call Stack(이하 스택)과 Heap Memory(이하 힙)로 구성되어 있습니다. 스택은 정적인 데이터를 저장하고, 힙에는 동적인 데이터를 저장하고 메모리 크기 역시 동적으로 할당된다고 합니다.
string, number 등의 원시 값 그리고 참조를 위한 주소의 경우 고정된 크기를 컴파일 시점에서 알 수 있어 스택에 저장되지만, 객체와 함수 등 참조 타입의 경우 컴파일 시점에서 크기를 알 수 있는 방법이 없어 힙 메모리에 저장됩니다.

원시 타입과 참조 타입의 차이

원시 타입과 참조 타입은 메모리에 데이터를 저장하는 방식에서 차이가 있습니다. 상기했던 설명과 같이 원시 타입의 경우 값을 스택에 저장하고, 참조 타입은 포인터를 스택에 저장하고, 값을 힙 메모리에 저장합니다.

원시 타입의 메모리 저장

let numOne = 50;
let numTwo = numOne; //numTwo와 numOne 모두 50이라는 값을 갖고 있음
numOne = 100;
console.log(numOne); // 100 출력
console.log(numTwo); // 50 출력

numOne변수와 numTwo 변수는 각각의 스택에 데이터가 저장되어 있으므로, numOne을 수정해도 numTwo 변수의 값에는 영향이 없습니다.


참조 타입의 메모리 저장


그림과 같이 객체 자체는 힙에 저장되고, 포인터는 스택에 저장됩니다. 포인터는 객체의 변수 이름으로 식별되고, 해당 객체를 가리킵니다.

let object1 = {
name:'Bingeh',
age:18
};
let object2 = object1;

// object1 의 age 속성을 업데이트
object1.age = 20;

console.log(object2); // object2의 age값도 업데이트 된 것을 확인할 수 있다.

object1 이라는 변수를 생성하고 객체를 할당합니다. 그 후 object2 라는 변수를 생성하고 object1 을 할당하면 원시 타입과 다르게 힙에 새로운 객체가 생성되지 않습니다. object1에 저장된 값은 객체를 가르키는 참조값, 즉 포인터입니다. object2 역시 객체의 데이터가 아닌 참조값을 담게 되었는데요,(얕은 복사) 결국 두 변수에서 바라보는 객체는 하나의 같은 객체이므로, object1만 업데이트해도 object2에 반영되는 것처럼 보이는 것입니다.😵‍💫

따라서 객체의 실제 값을 복사하고 싶다면(깊은 복사), Object.assign, 스프레드 연산자(...) 를 사용해야 합니다. 만약 2단 이상의 복잡한 객체라면 재귀함수, JSON 객체의 메서드를 이용하거나 lodash 등의 깊은 복사를 지원하는 라이브러리를 사용해 주어야 합니다. 🤧

const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListDeepCopy = JSON.parse(JSON.stringify(ingredientsList)); // 깊은 복사

마무리

자바스크립트 힘들고 어렵습니다,, 하지만 재밌습니다
이 세상의 모든 주니어 개발자들 화이팅입니다🥲

참고자료

profile
코딩하는 고양이🐱 / UI Developer, Front-end Developer

0개의 댓글