콜 스택과 메모리 힙 (Let && Const)

이상철·2021년 8월 1일
1

JavaScript

목록 보기
9/12
post-thumbnail
		 let myNumber = 23 

이 코드가 실행될 때 자바스크립트는 ,
1. 변수의 고유 식별자 (‘myNumber’)를 생성합니다.
2. 메모리에 주소를 할당합니다. (런타임에 할당될 것입니다.)
3. 생성된 주소에 값(value)을 저장합니다.우리는 보통 ‘myNumber 은 23과 같다’ 라고 말하지만 , 사실 더 정확하게 말하면
‘myNumber은 23 이라는 값(value)를 보유한 메모리 주소와 같다’ 라고 말해야 합니다.

이 개념의 차이를 아는것은 매우매우 중요한데요

만약 우리가 newVar 이라는 새 변수를 만들고 myNumber을 할당한다면,

let newVar = myNumber

…myNumber은 “0012CCGWH80” 이라는 메모리 주소와 같으므로, newVar도 23을 값(value)로 가지고 있는
메모리주소 ‘“0012CCGWH80”와 같게 됩니다.
즉, ’newVar 은 이제 23과 같습니다’ 라는 말과 같은 의미 인거죠


같은 주소에 두개의 식별자가 선언된 상태입니다.
myNumber는 메모리 주소 “0012CCGWH80”와 같으므로 newVar에 myNumber를 할당하면,
메모리 주소 “0012CCGWH80”이 newVar에 할당됩니다

만약 myNumber = myNumber + 1 이라고 입력하면 어떻게 될까요 ?
myNumber은 당연히 24라는 값을 가집니다.
그렇다면 newVar도 같은 메모리 주소를 가리키기 때문에 24란 값을 가질까요 ?
정답은 ‘아닙니다’ 입니다.

myNumber + 1 의 연산 결과가 24로 확인되면, 자바스크립트는 메모리에 새로운 주소를 할당합니다.
그리고 그 메모리의 값으로 24를 저장하고, myNumber은 이 메모리 주소를 가리키게 됩니다.
자바스크립트의 원시 타입 데이터는 변경불가능 하기 때문에 이런 방식으로 동작합니다.

자바스크립트의 메모리 모델 : 콜스택과 힙

콜스택은 원시타입이 저장되는 공간입니다.(함수 호출도 이 곳에 저장이 됩니다.)
우리가 지금까지 예시를 들었던, 변수를 선언했을 때의 상황들을 대략적인 표현을 그림으로 보자면 다음과 같습니다.

각 변수의 값을 보여주기 위해, 메모리 주소를 생략했습니다.
그러나, 변수는 값을 가지고있는 메모리 주소를 가리키고 있다는 사실을 잊으면 안됩니다.
이 사실이 let과 const에 대한 이해의 핵심이 되는 내용입니다.

이제, 힙을 살펴보죠.

힙은 원시타입이 아닌 타입들이 저장되는 공간입니다.
힙은 갑자기 데이터가 커질 수도 있는, 배열과 객체와 같은 정렬되지 않은 데이터들을 저장할 수 있다는 점이 핵심포인트입니다.

자바스크립트 참조 타입의 변수 선언과 할당
자바스크립트의 참조타입은 원시타입과는 다르게 동작합니다.
간단한 예부터 살펴보죠.
아래에서는 myArray 라는 변수를 선언하고 빈 배열로 초기화합니다.

let myArray = []
  • myArray 변수를 선언하고 ”[]“같은 참조타입을 할당 했을 때, 다음과 같은 일들이 메모리에서 일어나게 됩니다.
  1. 변수의 고유 식별자를 생성합니다.(“myArray”)
  2. 콜스택의 메모리에 주소를 할당합니다.(런타임에 할당될 것입니다.)
  3. 힙에 할당된 메모리 주소를 콜스택의 값(value)으로 저장합니다.(런타임에 할당될 것입니다.)
  4. 힙의 메모리 주소에 할당된 값(빈 배열 [])을 저장합니다.



여기에서, push나 pop (pop메서드는 배열에서 마지막 요소를 제거하고 그 요소를 반환합니다) 같은 메소드를 수행할 수 있습니다.

myArray.push(‘first’)
myArray.push(‘second’)
myArray.push(‘third’)
myArray.push(‘fourth’)	

let과 const

** 일반적으로, 가능한 한 const 를 사용해야하며 변수가 변경될거란 사실을 알 때만 let 을 사용해야합니다.
이 변경 이라는게 무슨 의미인지 명확히 짚고 넘어갑시다.
가장 큰 오해는, 이 변경 을 값(value)의 변경으로 해석하는 것입니다.
변경 의 의미를 오해하고 있는 자바스크립트 개발자는 다음과 같은 코드를 작성할 수 있습니다.

let sum = 0
sum =1 + 2 + 3 + 4 + 5
=> 15

let numbers = [ ]
numbers.push(1)
numbers.push(2)
numbers.push(3)
numbers.push(4)
numbers.push(5)

=> [1,2,3,4,5]
이 개발자는 값이 변경될 것임을 알았기에, let 을 사용하여 “sum”을 올바르게 표현했습니다.
그러나 push 메소드를 사용하여 배열에 무언가를 넣는 행위를, 값이 변경 됨으로 해석해버려서 let 을 사용하여 변수를 선언하는 실수를 저질렀습니다.

“변경”이란, 메모리 주소의 변경을 의미합니다.
let 은 메모리 주소를 변경을 허락합니다.
const 는 메모리 주소를 변경할 수 없습니다.

예를 들어 
const importantID = 489

무슨 일이 일어났는지 시각화해봅시다.
importantID 가 선언되면, 메모리 주소가 할당되고, 489라는 값(value)이 저장됩니다.
변수 importantID 는 메모리 주소와 같다는 점을 잊지마세요.**

const importantID = 100 // TypeError: Assignment to constant variable
100이라는 값이 importantID 에 할당되면, 100은 원시타입이기때문에 새로운 메모리 주소가 할당되고,
100이라는 값(value)이 그 메모리 주소에 저장됩니다.
그리고 자바스크립트는 그 새로운 메모리 주소를 importantID 에 할당하려고 시도하며 이 부분에서 에러가 발생합니다
const 를 사용해서 변수를 선언했다는 의미는 importantID 의 ID가 변하는 것을 원하지 않았다는 뜻이기에,
위 상황은 우리가 원하는 대로 동작하고 있다고 볼 수 있습니다.

-> importantID 에 100을 할당하면 실제로 100이 저장된 새로운 메모리 주소를 importantID에 할당하려고 합니다.
하지만 importantID는 const로 선언되었기 때문에 허용되지 않습니다.

배열은 변경할 수 있는 경우에만 유용한데 , const 는 이를 허용하지 않는데 왜 const를 사용하지 ..?라고 생각할 수 있습니다.
변경 은 메모리 주소에 의해 정의된다는 것을 다시 한 번 기억해야합니다.
배열을 const 로 선언하는 것이 왜 괜찮고, 왜 선호되는지 더욱 자세히 알아봅시다.

const myArray = []

myArray 가 선언되면 메모리 주소가 콜스택에 할당되고, 그 메모리 주소의 값(value)은 힙에 할당된 메모리 주소입니다.
힙에 저장된 값은 실제 빈 배열입니다.

여기서 만약

myArray.push(1)
myArray.push(2)
myArray.push(3)
myArray.push(4)
myArray.push(5)
해주면,

…push 메소드는 힙에 존재하는 배열에 숫자를 밀어넣습니다.
그러나, 변수 myArray의 메모리 주소는 변경되지 않습니다.
이것이 myArray 가 const로 선언되었지만 에러가 발생하지 않는 이유입니다.
myArray 는 여전히 “0458AFCZX91” 라는 메모리 주소와 같으며,
“0458AFCZX91”는 힙의 배열을 값(value)으로 가지는 “22VVCX011”를 값(value)으로 가지고 있습니다.

하지만

myArray = 3

이렇게 선언하면 에러가 갑니다. 왜냐하면
숫자 3은 원시 타입이기 때문에 콜스택의 메모리 주소가 할당되고,
3이라는 값이 저장되며, 그리고나서 이렇게 생긴 새로운 메모리 주소를 myArray 에 할당하려고 합니다.
그러나 myArray 는 const 로 선언되었기 때문에 이러한 과정은 허용되지 않습니다.

또 다른 오류의 예 인데요,
myArray = [‘a’]

[‘a’] 는 참조 타입인 배열이므로 콜스택에 새로운 메모리 주소가 할당되고,
콜스택 메모리 주소의 값(value)으로 힙 메모리 주소가 저장되며, 힙 메모리 주소의 값(value)은 [‘a’]입니다.

그런 다음 콜스택 메모리 주소를 myArray 에 할당하려 하면, 오류가 발생합니다.

const 로 선언된 객체의 경우에도 배열과 마찬가지로 참조 타입이므로,
key값을 추가하고 속성을 업데이트하는 등의 작업을 수행할 수 있습니다.

Const myObj = {}

myObj.name = ‘이상철’
myObj.age = 26

마지막으로..
자바스크립트 공부하다보면,

모든 지역 변수를 const나 let으로 선언해라.
변수를 재할당하지 않는 한, 기본적으로 const를 사용해라.
var 키워드는 절대 사용하지마라
에 대한 간단한 이유 몇가지 ..

  1. 미래의 버그를 사전에 방지한다.
  2. const 를 통해 선언된 변수는 반드시 선언과 동시에 초기화되어야하며,이를 통해 개발자는 스코프적인 측면에서 더욱 신중하게 변수를 배치해야함을 강요받게 됩니다. 이는 궁극적으로 더 나은 메모리 관리 및 성능으로 이어지게됩니다.
  3. 단지 코드를 보는 것 만으로도 어떤 변수가 변경불가능하고, 또 어떤 변수가 재할당이 가능한지 의사소통할 수 있기 때문입니다.

참고 기술블로그 : https://junwoo45.github.io/2019-11-04-memory_model/
이해하는데 많은 도움 주신 박준우님 감사합니다!

profile
헤더부터 푸터까지!!!

4개의 댓글

comment-user-thumbnail
2021년 8월 2일

안녕하세요 상철님! 든든한 개발자가 될 수 있도록 저도 많이 서포트해드리겠습니다 :)
개강해서 뵙기를 기다리겠습니다.🙌

1개의 답글
comment-user-thumbnail
2021년 8월 4일

이것이 바로 그 콜스택과 힙❗ 다시 보고 싶어서 들어왔어요👍

1개의 답글