• [JavaScript] 자바스크립트의 메모리 모델 ( 부제 : let vs Const )

    2021. 5. 20.

    by. KimBangg

    1. 머릿말

     

    이번에 올리는 포스팅은 아래의 글을 번역 하여서 올린 것임을 알립니다 !

    자바스크립트로 알고리즘을 공부하며,  단순 변수를 선언 했을 때와, 배열을 선언 하였을 때 어떤 차이를 가지는지 궁금하여 검색을 하던 도중 너무너무 유용한 글이라고 느껴서 공유 하게 되었습니다.

     

    https://medium.com/@ethannam/javascripts-memory-model-7c972cd2c239

     

    JavaScript’s Memory Model

    As programmers, declaring variables, initializing them (or not), and assigning them new values later on is something we do on a daily…

    medium.com

     

    2. 본문

     

    개발자로써, 다양한 변수를 선언하고 초기화하고 새로운 값을 선언하는 것은 매우 일반적인 일입니다.

     

    그러나 위와 같은 행동을 했을 때 무슨 일이 일어 날까요?

    과연 자바스크립트는 어떻게 이러한 기본적인 기능을 내부적으로 수행 하는 것이며, 그리고 과연 개발자가 이러한 내용을 아는 것은 도움이 될까요?

     

    저는 이번 포스팅을 통해 다음과 같은 내용을 다뤄 보려고 합니다.

     

    1. 변수 선언과 자바스크립트 원시 값 할당

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

    3. 변수 선언과 자바스크립트의 비원시값 할당

    4. Let vs Const

     

     

    1. 변수 선언과 자바스크립트 원시 값 할당

     

    간단한 이야기로 한번 시작해봅시다. 아래를 보면 저는 myNumber라는 변수를 선언하였고, 이를 23으로 초기화 하였습니다.

    let myNumber = 23

     

    1) 제가 만든 변수를 위한 유일한 식별자를 만듭니다.

    2. 메모리 주소 값을 할당 합니다. ( 런타임 중에 할당이 됩니다 )

    3. 마지막으로 23이라는 값을 주어진 메모리에 저장 합니다.

    우리는 일반적으로 myNumber와 23이 같은 숫자라고 말하고는 하지만, 기술적으로 더 정확한 표현은 "myNumber는 23이라는 값을 가지고 있는 메모리 주소와 같다" 라고 표현 해야합니다. 이러한 차이를 아는 것은 정말 정말 중요합니다.

     

    만약 우리가 newVar라는 변수를 선언하고, 여기에 myNumber를 할당한다면

    let newVar = myNumber

    myNumber는 기술적으로 “0012CCGWH80”과 같기 때문에, newVar도 마찬가지로 23라는 값을 가지고 있는  “0012CCGWH80” 과 같다고 할 수 있을 겁니다.

     

    즉, “newVar는 이제 23과 같습니다.”라는 말과 같다고 표현 할 수 있습니다.

     

    자, 이제 아래와 같은 일을 하면 무슨 일이 일어날까요?

    myNumber = myNumber + 1

    myNumber 변수는 24라는 값을 가지게 되는데 이 때 같은 주소를 가지고 있는 newVar의 값도 24로 변경이 될까요?

     

    정답을 말하자면, "아니요" 입니다. 왜냐하면 원시의 데이터 타입은 변화 하지 않는다는 (=immutable) 한 특징을 가지기 때문에, myNumber +1 이 24가 되면 JS는 새로운 주소 값을 제공하여, myNumber는 새로운 주소를 가지게 됩니다.

     

     

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

     

    이 포스팅의 목적상, 자바스크립트의 모델이 콜스택과 힙이라는 두 가지의 영역을 가지고 있다고 생각해봅시다.

    콜스택이란 원시 값이 저장되는 공간으로 함수의 호출도 이 곳에서 이루어집니다.

     

    우리가 지금까지 예시를 들었던, 변수를 선언했을 때의 상황들을 대략적인 표현을 그림으로 보자면 다음과 같습니다.

    앞으로 그려질 그림 속에서, 각각의 변수 값을 보여 주기 위해서 메모리 주소는 제거 하였습니다. 그러나, 변수가 값을 저장 하고 있는 메모리 주소를 가르키고 있다는 사실을 잊으시면 안됩니다 ! 이것이 바로 let vs const를 이해 할 수 있는 가장 중요한 열쇠가 될겁니다 :)

     

     이제는 힙에 대해서 살펴보겠습니다.

     

    힙은 비 원시 타입의 변수들이 저장 되는 공간입니다. 가장 중요한 점은 힙은 갑자기 데이터가 커질 수도 있는, 배열과 객체와 같은 정렬되지 않은 데이터들을 저장할 수 있다는 것 입니다.

     

    3. 변수 선언과 자바스크립트의 비원시값 할당

     

    비원시 데이터 타입은 원시 데이터 타입과 어떻게 다르게 움직이는지 비교해봅시다.

     

    간단한 예시 부터 시작해보죠. 아래는 myArray라는 배열을 선언하고 빈 값으로 초기화를 하였습니다.

    let myArray = []

    우리가 myArray라는 변수를 선언하고, []과 같은 비원시 데이터 타입을 할당하면 메모리 안에서는 무슨 일이 일어날까요?

     

    1) 제가 만든 변수를 위한 유일한 식별자를 만듭니다.

    2. 메모리 주소 값을 할당 합니다. ( 런타임 중에 할당이 됩니다 )

    3. 힙에 할당된 메모리 주소를 저장합니다.

    4. 힙에 저장된 메모리 주소는 배열에 할당된 값을 저장합니다.

     

     

    여기에서 우리는 push, pop 등 우리가 원하는 것들을 수행 할 수 있습니다.

    myArray.push("first")
    myArray.push("second")
    myArray.push("third")
    myArray.push("fourth")
    myArray.pop()

    4. Let vs Const

     

    일반적으론, 가능한 한 const 를 사용해야하며 변수가 변경 될 때만 let 을 사용해야합니다.

     

    여기서 우리는 "변경 된다는 것"이 무슨 의미인지 면밀히 다루어 보려고 합니다.

     

    일반적으로 사람들은 "변경 된다는 것"을 값(Value)이 변경된다고 잘못 생각하는데, 이러한 개발자들은 다음과 같이 코드를 작성합니다.

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

    이 개발자는 sum이라는 값이 변경될거라고 생각하여, sum 변수를 let으로 선언하였습니다.

    그러나 이 개발자는 number라는 배열 또한 let으로 선언을 하였는데, 이것은 잘못된 선언 방식입니다. 

     

    그렇다면 "변경"은 무엇을 의미하는걸까요? 이는 바로 "값" 의 변경이 아닌 "메모리" 주소의 변경을 의미합니다.

     

    이를 아래의 예시를 통해서 ! 이해 해보겠습니다.

     

    importantID 가 선언되면, 메모리 주소가 할당되고, 489라는 값(value)이 저장됩니다 변수 importantID 는 메모리 주소와 같다는 점을 잊지 않아야 합니다

     

    100이 importantID에 할당 됬을 때, 100은 원시 데이터 이기 때문에 새로운 주소가 할당되고 그 주소가 489라는 값을 저장합니다.그리고 그 다음 자바스크립트는 그 새로운 메모리 주소를 importantID 에 할당하려고 시도하며 이 부분에서 에러가 발생합니다.

    const 를 사용해서 변수를 선언했다는 의미는 importantID 의 ID가 변하는 것을 원하지 않았다는 뜻이기에, 위 상황은 우리가 원하는 대로 동작하고 있다고 볼 수 있습니다.

     

    위에서 언급 했던 것 처럼, 초보 개발자들은 let을 사용하여 배열을 선언하는데, 이것은 옳지 않고 배열을 선언 할 때는 반드시 "const"로 선언을 해주어야합니다. 이 개념은 처음에는 다소 혼란스러울수 있고, 직관적이지 않습니다. 

     

    주니어 개발자는 배열을 값을 변경 하기 위해서 사용할 때 유용하게 사용할 수 있다고 생각하는데 const가 값을 변경 시킬 수 없게 하는 이런 말도 안되는 상황을 주는데 도대체 이걸 왜 사용하는걸까? 라는 궁금증을 가질 수 있습니다.

     

    하지만 잊지마세요! const는 값을 변경 시키는 것이 아닌 주소를 변경 하는 것을 의미합니다. 이 내용을 아래의 예시로 통해 다뤄봅시다.

    const myArray = []

     

    처음에 myArray가 선언이 되고 콜스택에서 메모리 주소를 할당 받고, 힙에서 할당된 메모리 주소는 값을 저장합니다.

    힙에서 저장된 값은 현재는 비어있는 배열이고, 이를 가시화 해보겠습니다.

     

    만약, 다음과 같은 일을 하면

    myArray.push(1)
    myArray.push(2)
    myArray.push(3)
    myArray.push(4)
    myArray.push(5)

     

    

    힙에 저장된 메모리 주소의 Value는 변하지만, 실질적으로 myArray의 주소는 변화하지 않습니다.

    댓글