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 = []
여기에서, push나 pop (pop메서드는 배열에서 마지막 요소를 제거하고 그 요소를 반환합니다) 같은 메소드를 수행할 수 있습니다.
myArray.push(‘first’)
myArray.push(‘second’)
myArray.push(‘third’)
myArray.push(‘fourth’)
** 일반적으로, 가능한 한 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 키워드는 절대 사용하지마라
에 대한 간단한 이유 몇가지 ..
참고 기술블로그 : https://junwoo45.github.io/2019-11-04-memory_model/
이해하는데 많은 도움 주신 박준우님 감사합니다!
안녕하세요 상철님! 든든한 개발자가 될 수 있도록 저도 많이 서포트해드리겠습니다 :)
개강해서 뵙기를 기다리겠습니다.🙌