ES6 let

February 23, 2016

1. 글에 대해

  • 모든 결과는 Chrome 브라우저를 통해 테스트된 결과입니다.

2. ES5 & var

  • var 키워드를 통한 변수 선언

    • ES5 는 오직 function execution context 내부에서만 Isolated Scope(격리된 유효범위) 를 가질 수 있다.

      // global ec
      var a = 0;
      
      function A(){
      
          // A function ec
      
          // AFunctionEC.AO.a
          var a = 1;
      
          (function B(){
      
              // B function ec
      
              var a = 2;
      
              // BFunctionEC.AO.a
              console.log(a); // 2
          })()
      
          console.log(a); // 1
      }
      
      // globalEC.VO.a
      console.log(a); // 0
      
      A();
    • ES5클래스 기반 언어인 C or C++ 처럼, 블럭 내부에 Isolated Scope(격리된 유효범위) 를 가질 수 없다.

      // global ec
      var a = 0;
      
      if (true){
      
          // if 문 블럭 내부의 local context 를 갖지않는다.
          // 즉 선언된 변수 a 는 다른 값(1)으로 대치된다.
          var a = 1;
      }
      
      // globalEC.VO.a
      console.log(a); // 1

3. ES6 & let

  • let 키워드를 통해 선언된 변수는, 블럭 범위의 Isolated Scope(격리된 유효범위) 를 갖게된다.

    
    // global scope
    
    {
        // block scope
    
        // let 키워드를 통한 변수 선언
        let a = 1;
    }
    
    if (true){
        let b = 2;
    }
    
    switch (1){
        case 1:
            let c = 3;
            break;
    }
    
    for (let d = 0; d < 3; d++){
      console.log(d); // 0, 1, 2
    }
          
    
    let e = 4;
    
    
    try {
        // 실행 코드 처리 시, 블록 범위에 선언된 a 변수는 선언되지 않았다는 예외가 발생하게 된다.
        console.log(a);
    }
    catch(e){
        // a is not defined
        console.log(e.message);
    }
    
    try {
        // 실행 코드 처리 시, 블록 범위에 선언된 b 변수는 선언되지 않았다는 예외가 발생하게 된다.
        console.log(b);
    }
    catch(e){
        // b is not defined
        console.log(e.message);
    }
    
    try {
        // 실행 코드 처리 시, 블록 범위에 선언된 c 변수는 선언되지 않았다는 예외가 발생하게 된다.
        console.log(c);
    }
    catch(e){
        // c is not defined
        console.log(e.message);
    }
    
    try {
        // 실행 코드 처리 시, 블록 범위에 선언된 d 변수는 선언되지 않았다는 예외가 발생하게 된다.
        console.log(d);
    }
    catch(e){
        // d is not defined
        console.log(e.message);
    }
    
    console.log(e); // 4
  • let 키워드를 통해 선언된 변수유효 범위는 자신을 포함한 블럭 및 그 내부 블럭까지 유효하다.

    {
        let a = 1;
    
        {
            let b = 2;
    
            {
                let c = 3;
    
                {
                    let d = 4;
    
                    // 선언된 변수의 유효 범위는 자신을 포함한 블럭 및 그 내부 블럭까지 유효하다
                    console.log(a, b, c, d); // 1, 2, 3, 4
                }
            }
        }
    
    
        console.log(a); // 1;
    
        // 해당 블럭 Scope 에서는 b 변수에 접근할 수 없다.
        try{
            console.log(b);
        }
        catch(e){
            // b is not defined
            console.log(e.message);
        }
    
    }
  • 동일 블럭 범위에서, 동일한 식별자 이름으로 변수를 재 선언예외가 발생하게된다.

    // 동일 블럭 범위에서, 동일한 식별자 이름으로 변수를 재 선언시, 아래와 같은 예외가 발생하게된다.
    
    let a;
    // Uncaught SyntaxError: Identifier 'a' has already been declared
    let a;
    
    {
        let b;
        // Uncaught SyntaxError: Identifier 'b' has already been declared
        let b;
    }
    
    if (true){
        let i;
        let i; // Uncaught SyntaxError: Identifier 'i' has already been declared
    }
    
    (function A(){
        let c;
        let c; // Uncaught SyntaxError: Identifier 'c' has already been declared
    })();
    
    // 다른 식별자 이름으로 선언 시 예외가 발생하지 않는다.
    {
        let c;
        let d;
    
        console.log(d); // undefined
    }
  • let 키워드를 통해 선언된 변수EC 진입 및 실행 코드 처리 후에도 VO 의 새로운 속성으로 추가되지않는다.

    • 변수(a)가 Scope 에는 존재하지만, 초기화 되지않는 이 단계를 가리켜 Temporal Dead Zone(일시적 사각 지대)라고 부르며, 관련 예외 또한 모두 구현되어있다.

      // global ec 진입 시 VO 의 새로운 속성으로 추가되지않는다.
      try {
        console.log(a); // a is not defined
      }
      catch(e){
        console.log(e.message);
      }
      
      let a = 1;
      
      // 할당된 값을 반환한다.
      console.log(a); // 1
      
      // 실행 코드 처리후에도 VO 의 새로운 속성으로 추가되지않는다.
      console.log(window.a); // undefined
  • 동일 VO(AO) 범위에서, 동일한 식별자 이름으로 변수(or 함수) 선언예외가 발생하게 된다.(단 let 키워드를 통해 선언된 변수는 VO 의 속성으로 추가되지않는다)

    
    // 테스트 1
    // global ec
    let a;
    // globalEC.VO.a
    var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
    
    
    // 테스트 2
    // global ec
    let a;
    {
        // globalEC.VO.a
        var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
    }
    
    // 테스트 3
    // global ec
    let a;
    
    if (true){
        // globalEC.VO.a
        var a; // Uncaught SyntaxError: Identifier 'a' has already been declared
    }
    
    // 테스트 4
    // global ec
    let a;
    
    // globalEC.VO.a
    // Uncaught SyntaxError: Identifier 'a' has already been declared
    function a(){
    
        // a function ec
    }
    
    // 테스트 5
    // global ec
    let a;
    
    (function A(){
    
        // A function ec
    
        // 이 경우 a 변수는 globalEC.VO 의 속성으로 추가되며, 마찬가지로 예외가 발생하게된다.
    
        a; // Uncaught SyntaxError: Identifier 'a' has already been declared
    })();
          
       
    // 테스트 6            
    // global ec
    (function A(){
    
        // function ec
        
        let a;
    
        // 이 경우 a 변수는 AFunctionEC.AO 의 속성으로 추가되며, 마찬가지로 예외가 발생하게된다.
        var a;
    })();
       
    
    // 테스트 7
    // global ec
    let a;
    
    (function A(){
    
        // A function ec
    
        // 이 경우 a 변수는 AFunctionEC.AO 의 속성으로 추가되며, 예외가 발생하지않는다.
        var a;
    
        console.log(a); // undefined
    })();
    
  • 루프(for, while 등)문 내부에서 (let 키워드를 통해)선언된 변수는, 비동기 함수안에서 각기 다른 변수참조하게된다.(즉 각 루프는 서로 다른 변수(값)를 가지게 된다)

    
    // global scope
    
    // 루프 문 밖에서 let 키워드를 통해 선언된 변수
    let i = 0;
    
    for (;i < 10; i++) {
    
        // block scope
        window.setTimeout(function() {
            // 이 경우 i 변수는 최종 증감값인 10 을 반환하게된다.
            console.log(i); // 10
        });
    }
    
    // global scope
    
    // 루프문 내부에 let 키워드를 통해 선언된 변수
    for (let i = 0; i < 10; i++) {
    
        // block scope
        window.setTimeout(function() {
            // 이 경우 i 변수는 각기 다른 변수 값을 참조하게된다.
            console.log(i); // 0 ~ 9
        });
    }
    
    // global scope
    for (var i = 0; i < 10; i++) {
    
        // block scope
    
        // 루프문 내부에 let 키워드를 통해 선언된 변수
        let _i = i;
    
        window.setTimeout(function() {
            // 이 경우 _i 변수는 각기 다른 변수 값을 참조하게된다.
            console.log(_i); // 0 ~ 9
            // var 키워드를 통해 선언된 i 변수는, 함수 Scope Chain 매커니즘에 의해 최종 증감값인 10을 참조하게된다.
            console.log(i); // 10
        });
    }
    
    console.log(i); // 10;
    
    
    var i = 4;
    while (i) {
    
        // block scope
    
        let _i = i;
        // let 키워드를 통해 변수를 선언한다.
        window.setTimeout(function() {
            // 이 경우 _i 변수는 각기 다른 변수 값을 참조하게된다.
            console.log(_i); // 4 ~ 1
        });
    
        i--;
    }
    
    // 위 결과를 ES5 를 통해 구현한 방법은 아래와 같다.
    
    for (var i = 0; i < 10; i++){
    
        window.setTimeout(function(i){
    
            // Function.AO.i
            // bind 함수를 통해 바인딩된 AO.i 값을 참조하게 된다.
            console.log(i); // 0 ~ 9
        }.bind(null, i));
    }
    
    // 최종 증감값인 10을 반환하게된다.
    console.log(i); // 10
    
  • eval 함수를 통해, 선언된 변수(or 함수)는 local sandbox 안에서 평가된다.

    
    eval('let i');
    
    try{
        i;
    }
    catch(e){
        console.log(e.message); // i is not defined
    }
    

관련 URL


Profile picture

Written by mohwa