function func() {
for (var i = 0; i < 5; i++) {
var test = "test";
}
console.log(test); // test
}
func();
다음처럼 같은 이름의 변수를 중복선언하여도 문제가 없다. let이나 const로 변수를 중복선언한다면, SyntaxError가 발생하게 된다.
var hi = "hi";
var hi = "hello";
console.log(hi) // hello
function sayHi() {
console.log(hi); // undefined
var hi = "hi";
}
sayHi();
var hundred = 100;
console.log(window.hundred) // 100
블록 레벨 스코프
let
은 블록 레벨 스코프를 따른다. 변수 중복 선언 금지
let으로는 동일한 이름을 갖는 변수를 선언하면 SyntaxError가 발생하게 된다.
전역객체와 let
var로 선언한 변수를 전역변수로 사용하면, 전역객체의 프로퍼티가 되었다.
그러나, let으로 선언된 변수를 전역변수로 사용되어도 let 전역 변수는 전역 객체의 프로퍼티가 되지 않는다.
let은 보이지 않는 개념적인 블록 내에서만 존재한다.
let ten = 10;
console.log(window.ten) // undefined
const a = 10;
a = 200; // TypeError: Assignment to constant variable.
const ten = 10;
console.log(window.ten) // undefined
const bar; // SyntaxError: Missing initializer in const declaration
{
const constVar = 10;
}
console.log(constVar); // ReferenceError: constVar is not defined
객체를 const 변수의 타입으로 할당을 하면, 객체에 대한 참조를 변경하지 못한다.
const obj = { foo: 123 };
obj = { bar: 456 }; // TypeError: Assignment to constant variable.
그러나, 객체의 프로퍼티는 보호되지 않는다.
따라서 할당된 객체의 내용을 추가, 삭제, 수정할 수 있다.
const user = { name: "name" };
user.age = 10; // 프로퍼티 추가
user.name = "new name"; // 프로퍼티 변경
console.log(user); // { name: 'new name', age: 10 }
배열 또한 const 변수의 타입으로 할당을 한다면, 재할당은 불가능하다. 그러나, 배열의 요소를 변경하는 것은 가능하다.
const number = [];
for (let i = 0; i < 3; i++) {
number.push(i);
}
console.log(number); // [0,1,2]
자바스크립트는 let, const를 포함하여 모든 선언(var, let, const, function, class)를 호이스팅한다.
그러나 let으로 선언된 변수를 선언문 이전에 참조하면 ReferenceError가 발생한다.
그 이유를 알아보려면, 변수가 어떻게 생성되는지 알아야 한다.
변수 생성 과정
var로 선언된 변수는 선언단계(1)와 초기화 단계(2)가 한 번에 이루어진다.
따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하므로, 에러가 발생하지 않고 undefined를 반환하게 된다. 변수 할당문에 도달하면 값이 할당된다.
이러한 현상을 변수 호이스팅이라고 한다.
// 스코프의 초기에 선언 단계(1)와 초기화 단계(2)가 실행된다.
console.log(hello); // undefined
var hello; // 변수 선언문
console.log(hello); // undefined
hello = "hello"; // 할당문 -> 할당 단계(3)가 실행된다.
console.log(hello); // hello
// let은 스코프의 선두에서 선언단계(1)만 실행된다.
// 이 지점부터 초기화 단계 시작지점까지 TDZ이므로, 여기서 변수를 참조할 수 없다.
console.log(hello); // ReferenceError: Cannot access 'hello' before initialization
let hello; // 변수 선언문 -> 초기화 단계(2)가 실행된다.
console.log(hello); // undefined
hello = "hello"; // 할당문 -> 할당 단계(3)가 실행된다.
console.log(hello); // hello