JavaScript

[ES6 JavaScript] let, const

코딩하는 Jay 2020. 10. 5. 22:35
반응형

오늘은 let과 const에 대해 알아보겠습니다. ES6 이전에 변수를 선언하기 위해서 var를 사용했습니다. let은 var와 비슷하지만 몇가지 다른 점이 있습니다. 가장 큰 차이점은 let은 변수가 선언된 블록, 구문 또는 표현식 내에서만 유효한 것입니다. 예제를 보며 차이점을 알아보겠습니다.

 

Pixabay로부터 입수된 Esi Grünhagen님의 이미지 입니다.  

let

유효 범위 규칙

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // 상위 블록과 같은 변수!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // 상위 블록과 다른 변수
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

varTest();
letTest();

 위 예제는 let과 var를 테스트하는 코드입니다. var의 경우, x는 상위 블록과 같은 변수로서 if문 내부와 외부에서의 출력이 동일하게 2가 출력된 것을 확인할 수 있습니다. 하지만 let의 경우, if문 내부에서의 x와 외부에서의 x는 다른 변수로서 다른 결과를 출력하는 것을 확인 할 수 있습니다.

 

var x = 'global';
let y = 'global';
console.log(this.x); 	// "global" 전역 객체의 속성 x를 생성
console.log(this.y); 	// undefined 전역 객체의 속성 y를 생성하지 않음
console.log(y);		// "global"

 이뿐아니라 var의 경우엔 전역 객체의 속성을 생성하는데 반해, let은 전역 객체 속성을 생성하지 않습니다.

 

비공개 변수 모사

var Thing;

{
  let privateScope = new WeakMap();
  let counter = 0;

  Thing = function() {
    this.someProperty = 'foo';
    
    privateScope.set(this, {
      hidden: ++counter,
    });
  };

  Thing.prototype.showPublic = function() {
    return this.someProperty;
  };

  Thing.prototype.showPrivate = function() {
    return privateScope.get(this).hidden;
  };
}

console.log(typeof privateScope);	// "undefined"

var thing = new Thing();

console.log(thing);	// Thing {someProperty: "foo"}

console.log(thing.showPublic());	// "foo"

console.log(thing.showPrivate());	// 1

 let을 이용하여 클로저와 같은 구현도 가능합니다. let은 블록 스코프에만 유효하기 때문에 마치 클로저와 같이 동작합니다. 위 코드에서 privateScope WeakMap과 counter가 그렇습니다. 외부에서 접근할 수 없지만, thing 메서드 내부에서는 접근이 가능합니다.

 

임시적인 사각 지역과 오류

if (x) {
  let foo;
  let foo; // SyntaxError thrown.
}

 만약 같은 변수를 같은 함수나 블록 범위 내에서 재선언하면 SyntaxError를 발생시킵니다.

 

function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError
  var bar = 1;
  let foo = 2;
}

 그리고 let의 경우 호이스팅되지 않아 선언전에 참조할 경우 ReferenceError를 발생시킵니다. 그래서 "임시 사각 지역은" 블록 시작부터 변수 선언이 실행되기전까지입니다. 

 

// 'undefined' 출력
console.log(typeof undeclaredVariable);
// 'ReferenceError' 발생
console.log(typeof i);
let i = 10;

 let이 호이스팅되지 않았다고 undefined와 같다고 생각하면 안됩니다. 아예 선언되지 않은 변수는 undefined로서 typeof를 사용하면 undefined를 출력하지만, let으로 아래 선언한 경우, undefined가 아니라 ReferenceError를 발생시킵니다.

 

/////////////// 에러 ///////////////
let x = 1;
switch(x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // 재선언에 의한 SyntaxError.
    break;
}

/////////////// 가능 ///////////////
let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }  
  case 1: {
    let foo;
    break;
  }
}

 switch문의 경우 유의해야합니다. 위쪽 소스와 같이 switch 문은 블록이 하나이기 때문에 재선언에 의한 SyntaxError를 발생시킵니다. 같은 변수를 선언하고 싶다면 위 소스 아랫 부분과 같이 case문을 블록으로 감싸면 됩니다.

 

정적 유효 범위와 결합된 임시적인 사각 지역 예시

function test(){
   var foo = 33;
   if (true) {
      let foo = (foo + 55); // ReferenceError
   }
}
test();

 위 코드가 문제 없다고 생각될 수 있지만 실제 실행시 ReferenceError가 발생됩니다. 그 이유는 블록 내에 foo 변수가 이미 선언되었지만 선언 구문이 실행되기 전에 참조하고 있으므로 ReferenceError가 발생됩니다. 

 

function go(n) {
  // 정의되어 있는 n!
  console.log(n); // Object {a: [1,2,3]}

  for (let n of n.a) { // ReferenceError
    console.log(n);
  }
}

go({a: [1, 2, 3]});

 위 코드도 let n of n.a 부분에서 n을 선언하고 있지만 아직 선언이 실행되기 전에 n.a를 참조하려고 하므로 ReferenceError가 발생합니다.

 

 

const

 const는 let과 다른 점은 상수라는 것입니다. 한 번 초기화가 되면 그 값을 바꿀 수 없습니다.

 공통점은 let과 동일하게 블록 유효 범위를 같습니다. let에 적용되는 "일시적 사각 지대"에 관한 모든 것은 const에도 적용됩니다. 상수는 같은 범위의 상수 또는 변수와 그 이름을 공유할 수 없습니다.

const MY_FAV = 7;

 상수는 대소문자를 모두 사용할 수 있지만, 일반적으로 모두 대문자를 사용하여 선언합니다.

 

 

참고:

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let

 

let

let 구문은 블록 유효 범위를 갖는 지역 변수를 선언하며, 선언과 동시에 임의의 값으로 초기화할 수도 있다.

developer.mozilla.org

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const

 

const

const 선언은 블록 범위의 상수를 선언합니다. 상수의 값은 재할당할 수 없으며 다시 선언할 수도 없습니다.

developer.mozilla.org

 

반응형

'JavaScript' 카테고리의 다른 글

[ES6 JavaScript] Generator  (0) 2020.10.07
[ES6 JavaScript] for...of  (0) 2020.10.06
[ES6 JavaScript] Spread syntax(전개 구문)  (0) 2020.10.04
[ES6 JavaScript] Rest Parameters  (0) 2020.10.03
[ES6 JavaScript] default parameters  (0) 2020.10.02