본문 바로가기

자바스크립트

[js] 참조형 변수 '객체' 에 대해 알아보자

반응형

자바스크립트를 처음 배웠을 때, 참조형 변수는 객체 하나만 존재한다고 배웠습니다. 그런데, 참조형 변수가 무엇인가에 대한 설명을 들어보면 이게 뭔 말이지 싶은 경우가 많았습니다. 

 

그래서 이번 시간을 들여서 참조형 변수인 객체는 메모리에 어떻게 저장되는가에 대한 부분을 정리해보고자 합니다. 


참조형 변수

일단 다들 알다시피 자바스크립트에서 참조형 변수객체(object)입니다. 객체는 여러 개의 속성(property)으로 이루어져 있으며, 이 속성은 이름(key)과 값(value)으로 구성됩니다.

 

그리고, 자바스크립트에서는 다양한 종류의 객체를 지원합니다. 예를 들어, 배열(array), 함수(function), 날짜(date), 정규표현식(regular expression) 등이 모두 객체입니다. 객체는 변수에 할당될 수 있고, 함수의 인자로 전달될 수도 있습니다.

 

즉 위의 객체들은 겉으로는 보이지 않으나 내부적으로 키와 값으로 구성된다는 이야기 입니다.

다시말해,  위의 예시로 언급한, 배열, 함수, 날짜, 정규표현식은 모두 참조형 변수로서 메모리 주소를 가리키는 포인터가 저장됩니다.

 

참고로)포인터는 C언어에서 알 수 있듯이 해당 메모리 주소를 가리키는 화살표입니다. 

 

참조형 변수는 값이 아니라 메모리 주소를 가지고 있습니다. 따라서 참조형 변수를 다른 변수에 할당하면, 원본 변수와 할당된 변수는 같은 객체를 참조하게 됩니다. 이를 " 얕은 복사(shallow copy)"라고 부릅니다.

 

이와 달리 값형 변수는 메모리 주소의 메모리 공간에 저장된  값 자체를 복사합니다. 

 

** 값형 변수에 대해 추가적으로 알고자 한다면 클릭해보세요!

더보기
 // '카피' 변수는 원본 변수의 메모리에 저장된 실제 값인 123을 복사합니다.
 // 따라서 '원본'과'카피' 변수는 각각 별개의 값을 가지게 됨으로써
 // '원본' 변수의 값이 바뀌어도 '카피'변수의 값은 변하지 않습니다.
 let 원본 = 123;  
 let 카피 = 원본; 
 
 // 쉽게 말해 '원본'변수의 값을 234로 바뀌어도
 원본 =234;
 
 // '카피' 변수는 처음에 복사했던 123을 온전히 가지고 있습니다.
 // 앞서 말했듯 서로 독립된 메모리 공간에 값을 각각 가지고 있으니까요
 console.log(카피) // 출력결과) 123

 


객체 리터럴과 메모리 주소, 그리고 포인터

객체 리터럴은 어찌 보면 참조형 변수의 특징을 쉽게 살펴볼 수 있는 참조형 변수입니다. 

 

예를 들어, 다음과 같은 코드가 있다고 가정해봅시다. name 과 age , address 를 속성으로 가지고 있는 일반적인 객체리터럴 입니다. 

 

const person = {
 name :"John",
 age: 30,
 address: { 
     city: "Seoul", 
     street: "123 street"  
}
};

 

위 코드를 메모리 주소에 저장한다면 어떻게 저장될지 그려보면 다음과 같습니다.

 

  메모리 주소             값
+------------+     +---------------------------+
| 0x100      | --> | name: "John"              |
+------------+     +---------------------------+
| 0x104      | --> | age: 30                   |
+------------+     +---------------------------+       
| 0x108      | --> | address: {                |
+------------+     |   city: "Seoul",          |
                   |   street: "123 Main St."  |
                   | }                         |
                   +---------------------------+

위 코드를 살펴보면 , name : "John" 은 0x100 이라는 메모리 주소에 있는 공간에 저장되어 있고,

age 와 address 로 각각 자신의 메모리 주소에 위치한 공간에 저장되어 있습니다.

 

객체 리터럴은 이러한 메모리 주소와 값 중에서 메모리 주소를 가리키는 포인터(화살표)를 변수에 할당합니다.

 

즉, 다음과 같이 person 변수에 {  } 객체 리터럴을 저장하게 되면, {  } 내의 프로퍼티 속성과 값이 직접 저장되는 것이 아니라, 0x100 과 같은 메모리 주소를 가리키는 포인터(화살표)가 저장되는 것입니다.

const person ={ }

참조형 변수에 다른 변수를 할당하게 되면 어떻게 될까?

참조형 변수는 메모리에 저장된 실제 값이 아니라 메모리에 저장된 실제 값이 있는 위치인 메모리 주소를 가리키는 포인터가 저장된다고 하였습니다. 

 

그렇다면, 이러한 참조형 변수에 다른 참조형 변수를 할당하게 된다면 어떻게 될까요? 예를 들어 다음과 같이 말이죠.

let obj1 = {  //메모리 주소 0x1000를 가리키고 있는 화살표가 obj1 변수에 저장
  a:1,
  b:2
}

let obj2 = { //메모리 주소 0x2000를 가리키고 있는 화살표가 obj2 변수에 저장
 a:2,
 b:3
}

// obj2 에는 obj1 에 저장된 메모리 주소를 가리키는 화살표(포인터)가 저장
obj2 = obj1;

 

결론적으로 obj2는 ojb1 이 가리키고 있는 메모리 주소의 위치를 공유하므로, 서로 같은 메모리 주소의 공간을 공유하게 됩니다. 따라서 obj1  내의 프로퍼티와 값이 변경된다면 obj2도 똑같이 변경됩니다.

 


배열도 참조형 변수라고 하던데, 객체 리터럴과 같을까요?

아마 객체 리터럴을 살펴보면 배열에 대한 궁금증도 생길 것 같습니다. 제가 방금 생겨서 정리 해봅니다. 

let arr1 = [1, 2, 3];
let arr2 = arr1; // arr2는 arr1과 같은 배열 객체를 가리킴

arr1[0] = 100; // arr1의 첫 번째 요소를 변경
console.log(arr1); // [100, 2, 3]
console.log(arr2); // [100, 2, 3] (arr2에서도 같은 변경 사항이 반영됨)

배열도 마찬가지로 배열 변수 arr1 는 배열의 요소들이 각각 저장된 메모리 주소의 위치를 가리키는 포인터가 저장됩니다.

 

따라서, arr2 배열변수에 arr1 배열 변수를 복사하게 되면, arr2 배열변수도 arr1이 가지고 있는 포인터를 가지게 되므로, 서로 같은 메모리 주소 위치를 공유합니다.

 

다시 말해,  배열 arr1 변수 내의 값을 변경한다면, arr2 도 같은 메모리 주소를 공유하므로 해당 메모리 주소에 저장된 값이 변경되면 같은 변경내역을 공유하게 되는 것입니다.

 


함수나 정규표현식의 경우도 마찬가지로 이러한 방식에 따라 이루어지며, 이를 더 살펴보고 싶지만 저의 한계로 인해 다음 기회에 미뤄서 정리해 보고자 합니다. 

반응형