ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 변수var,let,const
    JavaScript/자바스크립트 기본 2023. 11. 15. 21:08

    1.메모리

    1+2

    컴퓨터는 위와 같은 연산이 있을 때 CPU를 사용해 연산하고, 메모리를 사용해 데이터를 기억한다.

    메모리는 데이터를 저장할 수 있는 메모리 셀(memory cell)의 집합체이다.

    각 셀은 메모리 주소를 갖는다. 이 메모리 주소는 메모리 공간의 위치를 나타낸다.

    이 메모리 공간에는 2진수로 처리된 모든 데이터들(이미지,텍스트,동영상 등)이 저장된다.

    예제 코드 1과 2는 메모리 상 임의의 주소에 저장되고 CPU는 이것을 읽어 연산을 수행한다.

    또한 연산을 통해 생성된 값 3도 메모리 상의 임의의 위치에 저장된다.

     

    하지만 연산 결과인 숫자 3은 현재 재사용할 수 없다.이 연산된 결과를 재사용 하고 싶다면 메모리 공간에

    직접 접근하는 방법 외에는 없다. 하지만 이러한 방법은 치명적 오류를 발생시킬 수 있다.

    따라서 자바스크립트는 개발자의 직접적인 메모리 제어를 허용하지 않는다.

    허용 한다 하더라도 값이 저장될 주소는 임의로 결정되는데 코드가 실행될 때 마다 매번 변경된다.

    이전에 저장된 주소를 알수도 없으며 알려주지도 않는다. 그래서 결과를 재사용을 하기 위해 변수라는메커니즘을 제공한다. 

    즉 변수란 값을 저장하기 위해 마련한 메모리 공간을 식별하기 위해 붙인 이름을 말한다.

     

    2.변수 선언

    변수를 사용하기 위해서는 반드시 선언이 필요하다. 만약 선언하지 않은 변수에 접근하면 ReferenceError가 발생한다.

    ReferenceError는 식별자를 통해 값을 참조하려 했지만 등록된 식별자가 없을 때 발생하는 에러다.

    자바스크립트 코드는 인터프리터에 의해 한 줄씩 순차 실행된다.

    변수 선언은 소스코드가 한 줄씩 순차 실행 되는 런타임(runtime)시점이 아닌 그 이전 단계에서 먼저 실행된다.

    런타임에 들어가기 앞서 소스코드의 평가 과정을 거치며 변수 선언을 포함한 모든 선언문을 소스코드에서 찾아내 먼저 실행시킨다.

    이러한 소스코드 평가 과정이 끝나면 비로소 변수 선언을 포함한 모든 선언문들을 제외하고 코드를 한 줄씩 실행 시킨다.

     

    자바스크립트 엔진은 변수 선언을 크게 2가지 단계에 거쳐 수행하고 사용자가 값을 할당하게 된다.

    1.선언 단계(Declaration Phase) : 변수의 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알림

    2.초기화 단계(Initialization Phase) : 값을 저장하기 위해 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화

    3.할당 단계(Assignment Phase) : undefined로 초기화 된 메모리에 사용자가 값을 할당하는 단계

     

    3.키워드 별 차이점

    변수를 선언할 때 사용할 수 있는 키워드는 다음과 같다.

    • var
    • let
    • const

    각각의 키워드가 갖는 특징에 대해 알아보자

    ①var

    1️⃣var 키워드를 사용한 변수 선언은 선언 단계와 초기화 단계가 동시에 진행된다.

    var result;

    즉 var result; 는 선언 단계를 통해서 result라는 변수 이름을 등록하고 초기화 단계를 통해

    undefined를 할당한다. 일반적으로 초기화란 변수가 선언된 이후 최초로 값을 할당하는 것을 말한다.

    이러한 초기화 단계가 없다면 확보된 메모리에 이전에 다른 애플리케이션이 사용한 값이 남아 있을 수 있다.

    이러한 값을 garbage value라고 한다. 따라서 메모리 공간을 확보하고 값을 할당하지 않은 상태에서

    바로 변수 값을 참조하면 쓰레기 값(garbage value)이 나올 수 있다.

    var 키워드는 선언과 동시에 암묵적으로 초기화를 수행하므로 이러한 위험으로부터 안전하다.

     

    2️⃣var키워드의 변수 호이스팅

    console.log(result); // undefined
    var result;
    result = 100;
    console.log(result) // 100

    선언되지 않은 변수에 접근하면 ReferenceError가 발생한다. 

    하지만 위의 코드가 RefernceError이 발생하지 않는 이유는 var키워드가 선언과 초기화 단계가 동시에 진행되고,

    런타임 이전에 변수 선언이 먼저 실행되었기 때문이다.또한 변수 선언문이 코드의 맨 위로 올려진 것처럼 실행되는 동작인

    호이스팅으로 인해 undefined가 출력되는것을 확인할 수 있다. 

     

    3️⃣var는 함수 스코프를 갖는다. 

    스코프란 유효 범위를 의미한다. 변수가 범위 내에서 접근 가능한지 불가능한지를 나타낸다. 

    함수 스코프를 갖는다는것은 다음과 같다.

    function scopeA(){
      var test = '함수 스코프';
    }
    console.log(test); //Uncaught ReferenceError: test is not defined

    var로 선언한 test 변수는 함수 스코프를 갖기 때문에 scopeA함수 내부에서만 접근가능하다.

    함수 밖에서 test변수에 접근하려고하면 에러가 발생한다.

    스코프에 대한 더 자세한 내용은 스코프 파트에서 작성한다.

     

    4️⃣var는 재선언과 재할당이 가능하다.

    var num =1;
    num = 2; //재할당이 가능
    var num =3; //재선언이 가능

     

    ②let

    1️⃣let 키워드는 선언 → 초기화 → 할당 단계를 거친다.초기화 단계는 실제 코드에 도달했을 때 실행된다.

    console.log(result); // --- TDZ
    let result;          // --- TDZ
    result = 100;
    console.log(result);

    위의 코드를 실행해보면 Uncaught ReferenceError: Cannot access 'result' before initialization

    이러한 에러가 표시되는걸 볼 수 있다. 초기화 되기 전 변수에 접근할 수 없다는 에러다.

    이것은 TDZ(Temporal Dead Zone)의 영향을 받아 발생하는 에러다.

    TDZ는 변수의 스코프 시작 지점에서 초기화 지점까지의 구간을 뜻한다.

    따라서 위 코드는 3번째 이전의 코드들이 TDZ의 영향을 받는다. 

    이 구간 안에서 초기화 되지않은 let변수를 호출할 경우 에러를 발생시킨다.

     

    2️⃣let은 블록 범위 스코프를 갖는다.

    var는 함수 스코프였다면, let은 블록{} 스코프를 갖는다. 블록 범위 스코프를 갖는것은 다음과 같다.

    if (true) {
      let blockScope = "블록스코프";
        console.log(blockScope); //블록 스코프
      if (true) {
        console.log(blockScope);//블록 스코프
      }
    }
    console.log(blockScope); //Uncaught ReferenceError: blockScope is not defined

    블록 내부에서는 외부에 접근할 수 있지만 블록 외부에서는 블록 내부의 let 변수에 접근할 수 없다. 

     

     

    3️⃣let도 호이스팅이 발생한다.

    let age = 100;
    function showAge(){
      console.log(age);
      let age = 20;
    }
    showAge(); //Uncaught ReferenceError:

    위의 예제는 var키워드와 마찬가지로 let도 호이스팅이 발생한다는걸 확인할 수 있다.

    만약 let이 호이스팅이 발생하지 않았다면 글로벌 스코프의 age = 100을 출력하겠지만, showAge라는 블록 스코프 안에서

    선언되있는 age가 호이스팅 되어 TDZ의 영향을 받아 ReferenceError가 발생한걸 확인할 수 있다.

     

    4️⃣let은 재할당은 가능하고 재선언은 불가능하다.

    let num = 0;
    num = 1;
    console.log(num); //1
    let num = 1; //cannot redeclare block-scoped variable 'num'.

     

    ③const

    1️⃣const는 선언과 초기화 할당이 한 번에 이루어진다.

    const age; //Uncaught SyntaxError: Missing initializer in const declaration
    const age = 1; //ok

     

    2️⃣let과 마찬가지로 블록 범위 스코프를 갖는다.

    3️⃣재선언과 재할당 둘 다 불가능하다. 

    const num = 0;
    num = 1;
    console.log(num); //1
    let num = 1; //cannot redeclare block-scoped variable 'num'.

     

     

      var let const 
    생성과정 선언+초기화 → 할당 선언→초기화→할당 선언+초기화+할당
    재할당 및 재선언 재할당,재선언 가능 재할당 가능 ,재선언 불가능 재선언, 재할당 불가능
    스코프 함수 스코프 블록 스코프 블록 스코프

     

     

     

     

     

     

     

    출처

    https://ko.javascript.info/variables

    모던 자바스크립트 DeepDive / 이웅모 저

Designed by Tistory.