오늘은 let과 const에 대해 알아보겠습니다. ES6 이전에 변수를 선언하기 위해서 var를 사용했습니다. let은 var와 비슷하지만 몇가지 다른 점이 있습니다. 가장 큰 차이점은 let은 변수가 선언된 블록, 구문 또는 표현식 내에서만 유효한 것입니다. 예제를 보며 차이점을 알아보겠습니다.
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
developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const
'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 |