인터넷 강의를 듣는데 강사님이 변수 선언을 할 때마다 var를 쓰셨다. 그래도 어디서 주워들은건 있어서 복습할 때 그것들을 무심코 const로 바꾸며 진행하던 중 한 에러를 만났다. 에러를 복사 붙여넣기하며 구글링을 하다가 원인은 내가 무심코 바꿨던 const였다는 것을 깨달았다. 그래서 이번 계기로 var, let, const, 더 나아가 scope와 hoisting에 대한 개념을 확실히 잡고 가야겠다는 생각이 들었다.
var fruits = "apple";
console.log(fruits); // apple
fruits = "banana";
console.log(fruits); // banana
var fruits = "grape";
console.log(fruits); // grape
변수를 한 번 선언한 이후에도 위 코드처럼 값의 재할당 및 재선언이 가능하다.
let fruits = "apple";
console.log(fruits); // apple
fruits = "banana";
console.log(fruits); // banana
let fruits = "grape";
console.log(fruits); // Uncaught SyntaxError: Identifier 'fruits' has already been declared
변수의 값은 재할당이 가능하지만, 변수명은 재선언이 불가능하다.
const fruits = "apple";
console.log(fruits); // apple
fruits = "banana";
console.log(fruits); // Uncaught TypeError: Assignment to constant variable.
const fruits = "grape";
console.log(fruits); // Identifier 'fruits' has already been declared
상수를 한 번 선언하면 이후 그 값을 재할당하거나 재선언하는 것이 불가능하다.
그런데 관련 책을 보던 중 '변수를 재할당할 수는 없지만, 값을 바꿀수는 있다.' 는 구절이 있어서 console 창에 간단한 코드를 작성해보았다.
const arr = [];
for (i = 0; i < 3; i++) {
arr.push(i);
}
console.log(arr); // [0, 1, 2]
이처럼 배열의 경우 값을 추가할 수 있었다.
이어서 다음과 같은 코드를 작성해 보았다.
const count = 10;
function canIBuy() {
count = -1;
if (count > 0) {
console.log("you can buy it");
} else {
console.log("you can't buy it");
}
}
canIBuy();
// Uncaught TypeError: Assignment to constant variable.
// at canIBuy (<anonymous>:3:11)
// at <anonymous>:11:1
상수 count를 10으로 선언한 뒤 canIbuy 함수 안에서 값을 변경하려고 시도해 보았다. const의 재할당 불가 특성상 당연히 에러가 나는 것이라고 생각했다. 그리고 다시 다음과 같이 함수 안의 count 앞에 const를 붙여서 실행해 보았다.
const count = 10;
function canIBuy() {
const count = -1;
if (count > 0) {
console.log("you can buy it");
} else {
console.log("you can't buy it");
}
}
canIBuy(); // you can't buy it
??? count의 값이 -1로 바뀌었다.
여기서 혼란스러워져서 친구에게 질문을 했더니 scope와 hoisting에 대해 검색해보라는 답을 얻었다.
예제 코드를 보면,
function house() {
let mouse_hole = true;
if (mouse_hole) {
const mouse_1 = '서울쥐';
let mouse_2 = '시골쥐';
var mouse_3 = '생떽쥐';
}
console.log(mouse_3);
}
house(); // 생떽쥐
var 로 선언한 생떽쥐는 if 문 안에서 선언되었더라도, if 문 밖 함수 house( ) 안에서 실행하면 문제없이 출력된다.
하지만 const나 let으로 선언한 서울쥐와 시골쥐를 같은 위치에 console.log로 입력해보면 다음과 같은 에러가 뜬다.
Uncaught ReferenceError: mouse_1 is not defined
at house (<anonymous>:9:17)
at <anonymous>:14:1
Uncaught ReferenceError: mouse_2 is not defined
at house (<anonymous>:9:17)
at <anonymous>:13:1
즉, var는 if 문 안에서 선언되었더라도 실행한 곳이 함수 안이기만 하면 실행이 되고, const나 let으로 선언한 변수는 if문 안에서만 실행이 되는 것을 알 수 있다.
간단히 var, let, const 별로 실행 제한범위가 정해져 있다고 생각하면 될 것 같다.
이 개념을 알고나서 위의 3. const 에서 count의 값이 왜 -1로 적용이 되는지 깨달았다.
함수 canIBuy( ) 안의 count는 밖에서 선언된 count와 별개로 함수 canIBuy( ) 안에서만 적용이 가능한 블록 레벨 스코프의 특성을 가진 상수라는 것을 알게 되었다.
console.log(mouse_1); // Uncaught ReferenceError
console.log(mouse_2); // Uncaught ReferenceError
console.log(mouse_3); // Undefined
const mouse_1 = '서울쥐';
let mouse_2 = '시골쥐';
var mouse_3 = '생떽쥐';
위 코드는 const, let, var로 각각 변수를 선언하기 전에 console.log로 실행시켰을 때의 결과를 보여준다.
생떽쥐의 코드만 보면 컴퓨터는 다음과 같이 해석한다.
var mouse_3;
console.log(mouse_3);
mouse_3 = '생떽쥐';
이것이 선언과 할당의 분리이다.
즉, var는 선언만 끌어올려질 뿐 값은 들어가기 전의 상태라 에러가 뜨지 않고 Undefined가 출력된다.
그럼 여기서 const나 let으로 선언한 서울쥐와 시골쥐는 호이스팅이 되지 않는다고 생각할 수 있다.
하지만 결론적으로 const와 let도 hoisting을 한다.
자세한 예시들은 참고 링크에 올려두겠다.
Ref.
책. 자바스크립트 코딩의 기술_길벗
https://www.youtube.com/watch?v=HsJ4oy_jBx0
https://gist.github.com/LeoHeo/7c2a2a6dbcf80becaaa1e61e90091e5d
https://velog.io/@bathingape/JavaScript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://medium.com/sjk5766/var-let-const-%ED%8A%B9%EC%A7%95-%EB%B0%8F-scope-335a078cec04
https://github.com/yalcodic/code-examples/blob/master/26_SCOPE/README.md