ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • let, const와 블록 레벨 스코프 - 문법 | Poiemaweb
    Javascript/ECMAScript 2015 (ES6) 2020. 2. 1. 12:35
    반응형

    [출처 : https://poiemaweb.com]

     

    ES5의 var 키워드

    1. 함수 레벨 스코프(Function-level scope)

    - 전역 변수의 남발

    - for loop 초기화식에서 사용한 변수를 for loop 외부 또는 전역에서 참조할 수 있다.

    2. var 키워드 생략 허용

    - 의도하지 않은 변수의 전역화

    3. 중복선언 허용

    - 의도하지 않은 변수값 변경

    4. 변수 호이스팅

    - 변수를 선언하기 전에 참조가 가능하다.

    ※ 전역 변수의 문제점

    - 유효범위(scope)가 넓어서 어디에서 어떻게 사용될 것인 파악하기 힘들다.

    - 비순수 함수(impure function)에 의해 의도하지 않게 변경될 수 있어서 복잡성을 증가


    let

    1. 블록 레벨 스코프

    대부분의 C-family 언어는 블록 레벨 스코프(Block-level scope)를 지원하지만 자바스크립트는 함수 레벨 스코프(Function-level scope)를 갖는다.

    더보기

    코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다.

    함수 레벨 스코프 (Function-level scope)

    블록 레벨 스코프 (Block-level scope)

    코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다.

    console.log(foo); // undefined
    var foo = 123;
    console.log(foo); // 123
    { var foo = 456; }
    console.log(foo); // 456

    키워드를 제공한다.

    let foo = 123;
    {
        let foo = 456;
        let bar = 456;
    }
    console.log(foo); // 123
    console.log(bar); // ReferenceError: bar is not defined

     

    2. 중복 선언 금지

    var 키워드로는 이름이 같은 변수를 중복해서 선언할 수 있었지만, let 키워드로는 이름이 같은 변수를 중복해서 선언하면 문법에러(SyntaxError)가 발생한다.

     

     

    3. 호이스팅(Hoisting)

    자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, function*, class)을 호이스팅한다.

     

    var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다.

     

    에 빠지기 때문이다.

    더보기

    변수는 3단계에 걸쳐 생성된다. 

    선언 단계 (Declaration phase)

    변수를 실행 컨텍스트의 변수 객체(Variable Object)에 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.

    초기화 단계(Initialization phase)

    변수 객체(Variable Object)에 등록된 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 변수는 undefined로 초기화된다.

    할당 단계(Assignment phase)

    undefined로 초기화된 변수에 실제 값을 할당한다.

    을 참조하기 바란다.

     

    var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.

    이라 한다.

     

    즉, 스코프에 변수를 등록(선언단계)하지만 초기화단계는 변수 선언문에 도달했을때 이루어진다. 초기화 이전의 변수에 접근하려고 하면 참조에러(ReferenceError)가 발생한다. 이는 변수가 아직 초기화되지 않았기 때문이다. 다시 말하면 변수를 위한 메모리공간이 아직 확보되지 않았기 때문이다. 따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없다. 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 ‘일시적 사각지대(Temporal Dead Zone; TDZ)‘라고 부른다.

     

    결국 ES6에서는 호이스팅이 발생하지 않는 것과 차이가 없어 보인다. 하지만 그렇지 않다.

    let foo = 1; // 전역변수
    {
        console.log(foo); // ReferenceError: foo is not defined
        let foo = 2; // 지역변수
    }

    위 예제의 경우, 전역 변수 foo의 값이 출력될 것 처럼 보이지만, ES6의 선언문도 여전히 호이스팅이 발생하기 때문에 참조에러(ReferenceError)가 발생한다.

    ES6의 let으로 선언된 변수는 블록 레벨 스코프를 가지므로 코드 블록 내에서 선언된 변수 foo는 지역 변수이다. 따라서 지역변수도 foo도 해당 스코프에서 호이스팅되고 코드 블록의 선두부터 초기화가 이루어지는 지점까지 일시적 사각지대(TDZ)에 빠진다. 따라서 전역 변수 foo의 값이 출력되지 않고 참조에러(ReferenceError)가 발생한다.

     

    4. 클로저

    var funcs = [];
    // 함수의 배열을 생성하는 for 루프의 i는 전역변수다.
    for (var i = 0; i < 3; i++) {
        (function (index) {
            funcs.push(function () { console.log(index); })
        }(i));
    }
    for (var j = 0; j < 3; j++) {
        funcs[j](); // 0, 1, 2
    }

    자바스크립트의 함수 레벨 스코프로 인하여 for 루프의 초기화 식에 사용된 변수가 전역 스코프를 갖게 되어 발생하는 문제를 회피하기 위해 클로저를 활용한 방법이다.

    var funcs = [];
    for (let i = 0; i < 3; i++) {
        funcs.push(function() { console.log(i); })
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();
    }

    5. 전역 객체와 let

    전역 객체(Global Object)는 모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window 객체, Server-side(Node.js)에서는 global 객체를 의미한다. var 키워드로 선언된 변수를 전역 변수로 사용하면 전역 객체의 프로퍼티가 된다.

    var foo = 123; // 전역변수
    console.log(window.foo); // 123

    let 키워드로 선언된 변수를 전역 변수로 사용하는 경우, let 전역 변수는 전역 객체의 프로퍼티가 아니다. 즉, window.foo와 같이 접근할 수 없다. let 전역 변수는 보이지 않는 개념적인 블록 내에 존재하게 된다.

    let foo = 123; // 전역변수
    console.log(window.foo); // undefined

    1. 선언과 초기화

    let은 재할당이 자유로우나 const는 재할당이 금지된다.

    또한, const는 let과 마찬가지로 블록 레벨 스코프를 갖는다.

    ※ 주의할 점

    const는 반드시 선언과 동시에 할당이 이루어져야 한다는 것이다. 그렇지 않으면 다음처럼 문법 에러(SyntaxError)가 발생한다.

     

    2. 상수

    - 상수는 가독성과 유지보수의 편의를 위해 적극적으로 사용해야 한다.

    - 네이밍이 적절한 상수로 선언되면 가독성과 유지보수성이 대폭 향상된다.

    const는 객체에도 사용할 수 있다. 물론 이 때도 재할당은 금지된다.

    const obj = { foo: 123 };
    obj = { bar: 456 }; // TypeError: Assignment to constant variable.

     

    3. const와 객체

    다시 말하자면 재할당은 불가능하지만 할당된 객체의 내용(프로퍼티의 추가, 삭제, 프로퍼티 값의 변경)은 변경할 수 있다.

    const user = { name: 'Lee' };
    user = {}; // TypeError: Assignment to constant variable.
    user.name = 'Kim';
    console.log(user); // { name: 'Kim' }

    만약에 명시적으로 객체 타입 변수의 주소값을 변경(재할당)하여야 한다면 let을 사용한다.


    KEYWORD

    - ES6를 사용한다면 var키워드는 사용하지 않는다.

    - 재할당이 필요한 변수에는 let을 사용한다.

    - 변경이 발생하지 않는(재할당이 필요 없는) 기본형 변수와 객체형 변수에는 const를 사용한다.


    Reference

    반응형

    댓글

Luster Sun