ES6 let

23 Feb 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

comments powered by Disqus