https://poiemaweb.com/es6-block-scope 을 토대로 공부한 내용을 정리한 것입니다.
키워드 : 스코프, 호이스팅, TDZ
var 키워드는 ES5까지 사용하던 방법이다.
4가지 특징을 가지고 있으며, 심각한 문제를 일으킬 수 있다.
함수 레벨 스코프(Function-level scope)
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.
var test = 'test'; // 전역 변수
console.log(test); // test
{
var test = 'change'; // 전역 변수
}
console.log(test); // change
문법적으로 문제는 없으나 변수 test의 값 'test'을 'change'로 재할당하여 덮어쓴다.
블록 레벨 스코프(Block-level scope)
모든 코드 블록(함수, if 문, for 문, while 문, try/catch 문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역 변수이다
let test = 'test';
{
let test = 'new test';
let number = 123;
}
console.log(test); // test
console.log(number); // ReferenceError: number is not defined
var test = 123;
console.log(test); // 123
number = 12345;
console.log(number); // 12345
var test = 'test';
var test = 'change';
let bar = 123;
let bar = 456; // Uncaught SyntaxError: Identifier 'bar' has already been declared
다음을 보자.
console.log(test); // Error: Uncaught ReferenceError: test is not defined
let test = 123;
console.log(test); // undefined
var test = 123;
호이스팅(Hoisting)이란?
var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다.
var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
즉, 선언문(ex. test = 123;) 이전에 접근해도 스코프에 변수(undefined)가 존재하기 때문에 에러가 발생하지 않는다.
이후 변수 할당문에 도달하면 값이 할당된다.
-> 이것을 변수 호이스팅이라고 한다.

let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다.
- 초기화 이전에 변수에 접근하게 되면 참조 에러가 발생하게 되는 것이다.
- 이는 변수를 위한 메모리 공간이 확보되지 않았다는 뜻이다.(= 초기화가 되지 않았다.)
- 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 일시적 사각지대(TDZ)라고 부른다.

그렇다면 ES6에서(let, const)는 호이스팅이 발생하지 않는 것과 같지 않나?
나도 그런 줄 알았으나 다음 예제를 보면 그렇지 않다는 것을 알 수 있다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: foo is not defined
let foo = 2; // 지역 변수
}
자바스크립트의 전역 객체는 일반적으로 브라우저 측에서는 window, 서버 측에서는 process와 같은 전역 객체를 의미한다.
암묵적으로 사용되어 생략되는 경우가 많다고 알고 있는데...
하여튼 var의 경우 다음과 같은 전역 객체의 프로퍼티가 된다.
var foo = 123; // 전역 변수
console.log(window.foo); // 123
하지만 let은 다르다.
let foo = 123; // 전역 변수
console.log(window.foo); // undefined
const는 let과 대부분 동일하나 다음과 같은 차이점을 가지고 있다.
const FOO = 123;
FOO = 456; // TypeError: Assignment to constant variable.
const FOO; // SyntaxError: Missing initializer in const declaration
// 값의 의미를 명확히 기술하여 가독성이 향상되었다.
const MAXROWS = 10;
if (rows > MAXROWS) {}
const user = { name: 'Lee' };
// const 변수는 재할당이 금지된다.
// user = {}; // TypeError: Assignment to constant variable.
// 객체의 내용은 변경할 수 있다.
user.name = 'Kim';
console.log(user); // { name: 'Kim' }
const test = [1];
console.log(test); // [ 1 ]
test.push(2);
console.log(test); // [ 1, 2 ]