자바스크립트의 유연성에서 오는 단점을 보안하기 위해 ES2015에서 let
, const
가 추가되었다.
(부끄럽지만 아직 나의 코드리뷰에는🙈) const
를 쓰라는 코멘트가 달리고 있기에...
var
, let
, const
의 차이점을 정리해보려 한다.
var
은 아래와 같이 재선언, 재할당이 모두 가능하다.
var name = 'Kevin';
console.log(name); //"Kevin"
var name = 'Jessica';
console.log(name); //"Jessica"
name = 'Jessie';
console.log(name); //"Jessie"
let
은 재선언은 되지 않으며, 재할당만 가능하다.
let fruit = "melon";
console.log(fruit); //"melon"
let fruit = "banana";
console.log(fruit); /*"SyntaxError: Identifier 'fruit' has already
been declared"*/
fruit = "strawberry";
console.log(fruit); //"strawberry"
const
는 재선언과 재할당 모두 불가능하다. 따라서 상수(변하지 않는 값)에 사용한다. 또한 const
는 반드시 선언과 동시에 할당이 이루어져야 한다.
+const
와 같이 immutable value(상수)는 대문자로 선언하는 것이 일반적이다.
const CAT; /*"SyntaxError: Missing initializer in const declaration"*/
const CAT = "Meow";
console.log(CAT); //"Meow"
const CAT = "Woof";
console.log(CAT); /*"SyntaxError: Identifier 'cat' has already been
declared"*/
CAT = "Woof";
console.log(CAT); //"TypeError: Assignment to constant variable."
+const
로 선언된 변수에 재선언과 재할당은 불가능하나, const
에 할당된 객체(배열 및 함수 포함)에 변화를 주는 것은 가능하다.
//이건 가능!
const FRUITS = ["apple", "banana", "grape"];
FRUITS = ["strawberry", "kiwi", "melon"]; /*Uncaught TypeError: Assignment
to constant variable.*/
FRUITS[2] = "orange";
console.log(FRUITS); //["apple", "banana", "orange"]
//이것도 가능!
const ARR = [1, 2, 3];
ARR.length = 0;
console.log(ARR); //[]
함수레벨스코프(function-level scope): 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.
블록레벨스코프(block-level scope): 모든 코드 블록(함수, if문, for문, while문, try/catch문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다.
-poiemaweb.com
var
와 let
의 첫번째 차이점은 scope!
var
은 함수레벨스코프로, 함수의 코드 블록만을 스코프로 인정한다. 따라서 for문의 변수 선언문에서 선언한 변수를 for문 밖에서도 참조할 수 있고, if문 안에서 선언된 변수도 밖에서 참조할 수 있다.
var x = 5;
if(true) {
var y = 2;
}
console.log(x * y); //10
if문 내부에 있다해도 x와 y는 모두 전역변수이기 때문이다.
같은 이유로 함수블록 안에서 전역스코프 내 변수와 동일한 이름을 사용한다해도 override되지 않는다.
var outerWear = "T-Shirt";
function myOutfit() {
var outerWear = "Sweater";
return outerWear;
}
console.log(myOutfit()); //Sweater
console.log(outerWear); //T-Shirt
하지만 let
과 const
는 블록레벨스코프를 따른다. let
의 스코프를 결정하는 것은 중괄호{}이다. 중괄호를 기준으로 스코프가 정해지기 때문에 중괄호 안에서 선언된 let
과 const
는 바깥에서 쓸 수가 없다.
for(let i = 0; i < 5; i++) {
a = i + 2;
console.log(i); //0, 1, 2, 3, 4
}
console.log(i); //ReferenceError: i is not defined
위 예문의 조건문에서 선언된 let
은 for문 안에서만 쓸 수 있도록 선언된 것으로, 전역스코프의 console.log(i)
로는 접근할 수가 없다.
var
를 이용해 전역변수를 만들면 window객체에 key와 value로 추가되지만,
let
이나 const
를 이용해 전역변수를 만들면 window 객체에 추가되지는 않는다.
var a = "apple";
console.log(window.a); //"apple"
let b = "banana";
console.log(window.b); //undefined
const c = "strawberry";
console.log(window.c); //undefined
호이스팅: 자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, function*, class)을 호이스팅한다. 호이스팅(Hoisting)이란, var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다.
-poiemaweb.com
var
로 선언된 변수와 let
으로 선언된 변수는 호이스팅에서 다음과 같은 차이가 나타난다.
console.log(she); //undefined
var she;
console.log(he); //Cannot access 'he' before initialization
let he;
이러한 차이가 나타나는 이유는 뭘까? let
은 호이스팅이 되지 않는 것일까?
그렇지 않다.
앞서 인용된 문장과 같이 자바스크립트는 let, const를 포함하여 모든 선언(var, let, const, function, function*, class)을 호이스팅한다.
자세히 들여다보면, error메세지 상의 Cannot access는 호이스팅이 되어 밑에 let이 존재한다는 것을 알고있다는 뜻이 된다.
이 부분을 이해하려면 let
으로 변수가 생성되는 단계를 알 필요가 있다.
let
으로 3단계에 걸쳐 변수를 생성한다.
1) 선언 단계(Declaration phase)
변수를 실행 컨텍스트의 변수 객체(Variable Object)에 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.
2) 초기화 단계(Initialization phase)
변수 객체(Variable Object)에 등록된 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 변수는 undefined로 초기화된다.
3) 할당 단계(Assignment phase)
undefined로 초기화된 변수에 실제 값을 할당한다.
-poiemaweb.com
선언과 동시에 초기화가 이루어지는 var
와는 다르게 let
은 해당 선언문이 실행되기 전까지 초기화 단계가 이루어지지 않는다. 초기화로 값이 정해지지 않은 let
에 접근 시 위 예제와 같이 ReferenceError: Cannot access before initialization
에러가 발생한다.
이렇게 let
으로 변수 선언 후 실행되기 전 사이의 구간을 ❗️Temporal Dead Zone(TDZ)❗️이라고 한다.
변수 선언 시, 가독성과 유지보수의 편의를 위해서는 기본적으로 const
를 사용한다(상수라면 특히 더!). 이는 의도치 않은 재할당을 방지해준다.
let
은 재할당이 필요한 경우에 한하여 사용하는 것이 좋으니 (재선언이 아닌)재할당이 필요하다고 판단될 때 const
를 let
으로 바꿔주면 된다.
ES6를 따른다면var
사용은 권장하지 않는다.
*본 포스팅은 아래 사이트들을 참고 및 인용하여 작성되었습니다.
학습단계로 잘못된 정보가 있을 수 있습니다. 잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다 😊
https://poiemaweb.com/es6-block-scope
https://velog.io/@bathingape/JavaScript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone