var x = 1;
var y = 1;
// var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언 허용
// 초기화문이 있는 경우: var 키워드가 없는 것처럼 동작
var x = 100;
console.log(x); // 100
// 초기화문이 없는 경우: 변수 선언문 무시
var y;
console.log(y); // 1
함수 레벨 스코프
var 키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정
var x = 1;
// if문의 변수 선언문에서 var 키워드로 선언한 변수도 전역변수가 됨
if (true) {
var x = 10;
}
console.log(x); // 10
// for문의 변수 선언문에서 var 키워드로 선언한 변수도 전역변수가 됨
for (var x = 0; x < 5; x++) {}
console.log(x); // 5
변수 호이스팅
var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프의 선두로 올려진 것처럼 동작
할당문 이전에 변수를 참조할 경우 undefined 반환
// 이 시점에
// 1. 호이스팅에 의해 변수 foo는 이미 선언
// 2. foo는 undefined로 초기화
console.log(foo); // undefined
foo = 123;
console.log(foo); //123
// 변수 선언은 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 실행
var foo;
let 키워드
변수 중복 선언 금지
let 키워드로 이름이 같은 변수를 중복 선언하면 문법 에러 발생 SyntaxError
var foo = 123;
// var 키워드 중복 선언 허용
// 아래 변수 선언문은 var 키워드가 없는 것처럼 동작
var foo = 456;
let bar = 123;
// let이나 const 키워드로 선언된 변수는 같은 스코프 내에서 변수 중복 선언 허용 x
let bar = 456; // SyntaxError: Identifier 'bar' has already been declared
블록 레벨 스코프
let 키워드로 선언한 변수는 모든 코드 블록 (함수, if 문, for문, while문, try/catch 문 등)을 지역 스코프로 인정하는 블록 레벨 스코프 block-level scope를 따름
블록 레벨 스코프의 중첩
변수 호이스팅
var 키워드로 선언한 변수와 달리 let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것처럼 동작
let 키워드로 선언한 변수는 "선언 단계"와 "초기화 단계"가 분리되어 진행
초기화 단계가 실행되기 이전에 변수를 접근하려고 하면 참조 에러 ReferenceError 발생
일시적 사각지대 TDZ; Temporal Dead Zone: 스코프의 시작 시점부터 초기화 시작 시점까지 변수를 참조할 수 없는 구간
호이스팅이 발생하지 않는 것처럼 동작하는 것이지 실제로 호이스팅은 발생
console.log(foo);
// 브라우저: ReferenceError: foo is not defined
// NodeJs: ReferenceError: Cannot access 'foo' before initialization
let foo;
// var
// 선언한 변수는 런타임 이전에 선언 단계와 초기화 단계가 실행
// 따라서 변수 선언 이전에 변수를 참조 가능
console.log(foo); // undefined
var foo;
console.log(foo); // undefined
foo = 1;
console.log(foo); // 1
// let
// 런타임 이전에 선언 단계가 실행 / 초기화는 진행 x
// 초기화 이전의 일시적 사각 지대에서는 변수 참조 불가능
console.log(bar); // ReferenceError: Cannot access 'bar' before initialization
let bar; // 변수 선언문에서 초기화 실행
console.log(bar); // undefined
bar = 2; // 할당문에서 할당 실행
console.log(bar); // 2
var vs let 변수의 생명주기
// let의 호이스팅
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: Cannot access 'foo' before initialization
let foo = 2; // 지역 변수
}
전역 객체와 let
var 키워드로 선언한 전역 변수와 전역 함수, 선안하지 않은 변수에 값을 할당한 암묵적 전역은 전역 객체 window의 프로퍼티가 됨
참고: 전역 객체의 프로퍼티를 참조할 때 window를 생략할 수 있음
let 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아님
let 전역 변수는 보이지 않는 개념적인 블록(전역 렉시컬 환경의 선언적 환경 레코드) 내에 존재
// 전역 변수
var x = 1;
// 암묵적 전역
y = 2;
// 전역 함수
function foo() {}
// var키워드로 선언한 전역 변수는 전역 객체 window의 프로퍼티
console.log(window.x); // 1
// 전역 객체 window의 프로퍼티는 전역 변수처럼 사용 가능
console.log(x); // 1
// 암묵적 전역은 전역 객체 window의 프로퍼티
console.log(window.y); // 2
console.log(y); // 2
// 함수 선언문으로 정의한 전역 함수는 전역 객체 window의 프로퍼티
console.log(window.foo); // ƒ foo() {}
console.log(foo); // ƒ foo() {}
let x = 1;
// let, const키워드로 선언한 전역 변수는 전역 객체 window의 프로퍼티가 아님
console.log(window.x); // undefined
console.log(x); // 1
const 키워드
const 키워드는 상수 const를 선언하기 위해 사용
반드시 상수만을 위해 사용하지는 않음
선언과 초기화
const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 함
let 키워드와 마찬가지로 블록 레벨 스코프, 변수 호이스팅이 발생하지 않는 것처럼 동작
// const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화
const foo = 1;
const bar // SyntaxError: Missing initializer in const declaration