## 자바스크립트의 변수 선언 방식 자바스크립트에서 변수를 선언하는 키워드는 3가지 종류가 있다. | 선언 방식 | 도입 시기 | 스코프 | 재선언 | 재할당 | 호이스팅 | | ------- | ------ | --- | --- | --- | -------------- | | `var` | ES5 이전 | 함수 | ⭕️ | ⭕️ | undefined로 초기화 | | `let` | ES6 | 블록 | ❌ | ⭕️ | TDZ | | `const` | ES6 | 블록 | ❌ | ❌ | TDZ | ## var ```javascript var a = 1; ``` var는 자바스크립트의 초기부터 사용된 키워드이고 함수 스코프를 갖는다. ```javascript function example() { if (true) { var message = 'Hello'; // 블록 내에서 선언 } console.log(message); // 'Hello' - 함수 전체에서 접근 가능 } ``` <!--todo: 함수 스코프란 --> 같은 스코프 내에서 재선언과 재할당이 가능하다. ```javascript var language = 'JavaScript'; var language = 'TypeScript'; // 재선언 가능 language = 'Python'; // 재할당 가능 ``` [[호이스팅과 TDZ#호이스팅이란?|호이스팅]]으로 인해서 선언이 스코프의 최상단으로 끌어올려지고, undefined로 초기화된다. ```javascript console.log(name); // undefined (에러 발생하지 않음) var name = 'JavaScript'; console.log(name); // JavaScript ``` var는 아래와 같은 문제점이 있었고, 이를 보완할 수 있는 `let`과 `const` 키워드가 ES6에 등장했다. - 블록 스코프 미지원으로 인한 예상치 못한 동작 - 전역 객체 오염 - 재선언으로 인한 실수 가능성 <!--todo: 왜 var는 이렇게 설계되었을까.--> ## let ```javascript let b = 2; ``` let은 const와 함께 ES6에 등장한 변수 선언 키워드이다. var와는 다르게 **블록 스코프**를 갖는다. ```javascript if (true) { let blockVar = 'block scoped'; console.log(blockVar); // 'block scoped' } console.log(blockVar); // ReferenceError: blockVar is not defined ``` var와 동일하게 재할당은 가능하지만, 재선언은 불가능하다. ```javascript let count = 1; count = 2; // 재할당은 가능 let count = 2; // SyntaxError: Identifier 'count' has already been declared. ``` var와 동일하게 [[호이스팅과 TDZ#호이스팅이란?|호이스팅]]으로 인해서 선언이 스코프의 최상단으로 끌어올려지지만, [[호이스팅과 TDZ#TDZ 란?|TDZ]]로 인해서 선언 이전에 접근할 경우에는 ReferenceError가 발생한다. ```javascript console.log(age); // ReferenceError: Cannot access 'age' before initialization let age = 25; ``` ## const ```javascript const c = 3; ``` const는 let과 함께 ES6에 새로 등장한 키워드이다. 불변한 값을 명시적으로 선언하는 방법으로 let과 달리 **재선언과 재할당이 모두 불가능**하다. ```javascript const name = "JS"; const name = "JavaScript"; // SyntaxError: Identifier 'name' has already been declared. name = "JavaScript"; // TypeError: Assignment to constant variable. ``` [[데이터 타입#참조 타입|참조 타입]]의 경우 내부 값은 변경 가능하다. ```javascript const obj = { name: "JS" }; obj.name = "JavaScript"; // 객체 내부 변경은 가능 ``` let과 동일하게 **블록 스코프**를 갖는다. const도 var와 let과 동일하게[[호이스팅과 TDZ#호이스팅이란?|호이스팅]]으로 인해서 선언이 스코프 최상단으로 끌어올려지지만 const의 경우 재할당이 불가능하기 때문에 **명시적인 초기화가 없다면 에러가 발생**한다. ```javascript const name; // SyntaxError: Missing initializer in const declaration. name = "JavaScript"; ``` ## 유명한 (...) var와 반복문, 그리고 let ~~정리 예정~~ ```javascript // var의 문제점 for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); // 3, 3, 3 } ``` ```javascript // let으로 해결 for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); // 0, 1, 2 } ``` ## 관련 링크 - [[호이스팅과 TDZ]]