let, const가 나오기 이전에는 var를 사용했다. 그렇다면, var와 let, const의 차이는 무엇일까. 핵심은 var는 함수스코프, let, const는 블록단위 스코프를 가진다는 것이다. 그 외에도 선언, 할당, 호이스팅 등의 특징을 발견할 수 있다.
블록 안에서 변수를 변경하면, 전역공간의 변수까지 변경된다. 그 이유는 var는 함수단위 스코프를 가지기 때문이다.
let/const는 블록단위로 변수의 범위가 지정된다.
전역공간은 사용하면 안될까? 그렇다면 그 이유는 무엇인가? 어디서나 접근이 가능하기 떄문이다. 사람이 생각하기에 분리되어있다 생각하지만, 실행혼경에서는 분리되어있지 않다. 핵심은 의도치 않는 에러가 발생하기 때문이다.
그래서, 에러를 방지하기 위한 방안으로는 전역변수를 사용하지 않는다. window/global을 조작하지 않는 것이다. const/let을 사용함으로 var가 전역에 생성하는 데이터를 줄일 수 있다. 보다 근본적으로
IIFE, Module, Closure를 통해 스코프를 나누는 방법이 있다.
전역공간은 대체로 최상위를 의미한다. window 혹은 global 이라고 하는데 브라우저 환경에서는 window, node환경에서는 global이 전역공간이다.
JS는 파일을 나눠도 스코프가 나뉘어지지 않는다.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./global.js"></script>
<script src="./global2.js"></script>
</body>
</html>
// global
var global = 'global';
console.log(console.log('global', global));
// global2
console.log('global2', global);
또한 전역객체에 이미 등록되어있는 기능들과 같은 이름의 변수를 선언/할당하면, 그 기능에 덮어서지는 문제가 생긴다. 브라우저 콘솔에는 에러가 찍히지만, 노드 환경 내에서는 에러가 생기지 않는다.
// global
var global = 'global';
console.log(console.log('global', global));
var setTimeout = 'setTimeout';
// global2
console.log('global2', global);
setTimeout(() => {
console.log(1);
}, 1000);
호이스팅은 런타임 시기에 선언과 할당이 분리된 것이다. 런타임 시기는 코드가 동작될 떄는 의미한다. 호아스팅은 변수가 초기화가 제대로 되어있지 않을 때 undefined로 최상위에 끌어올려질 수 있는 것을 의미한다. 특히 var를 사용할 때 발생가능하다.
var globa = 0;
function outer() {
console.log(global); // undeinfd > 선언과 할당이 분리된 상태
var global = 5;
function inner() {
var global = 10;
console.log(global); // 10
}
inner();
global = 1;
console.log(global); // 1
}
outer();
변수뿐만 아니라 함수 역시 호이스팅이 된다.
console.log(sum()); // 3
function sum() {
return 1 + 2;
}
해결책 중 하나는 함수표현식을 사용하는 것이다.
console.log(sum()); // Error
const sum = function() {
return 1 + 2;
}
호이스팅은 런타임시 선언이 최상단으로 끌어올려지는 것을 의미한다. 문제는 코드 작성시 예측하지 못한 실행결과가 나올 수 있다. 이것을 피하기 위해 var를 사용하지 말아야 한다. 그리고 함수도 호이스팅이 되기 때문에 함수 표현식을 통해 호이스팅을 방지할 수 있다.
let/const선언 변수는 호이스팅되지 않는 것이 아니다. 스코프에 진입할 때 변수가 만들어지고 TDZ(Temporal Dead Zone)가 생성되지만, 코드 실행이 변수가 실제 있는 위치에 도달할 때까지 액세스할 수 없는 것이다. let/const변수가 선언된 시점에서 제어흐름은 TDZ를 떠난 상태가 되며, 변수를 사용할 수 있게 된다.
TDZ는 선언 전에 변수에 접근하는 것을 금지한다.