자바스크립트는 렉시컬 스코프를 따르므로 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위 스코프를 결정한다. 함수가 호출된 위치는 상위 스코프 결정에 아무런 영향도 주지 않는다. 즉, 함수의 상위 스코프는 언제나 자신이 정의된 스코프다.
함수 정의가 실행되어 생성된 함수 객체는 정적으로 결정된 상위 스코프를 기억한다. 함수가 호출될 때마다 함수의 상위 스코프를 참조할 필요가 있기 때문이다.
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
변수의 생명 주기는 메모리 공간이 할당된 시점부터 메모리 공간이 해제되어 가용 메모리 풀(memory pool)에 반환되는 시점까지다.
변수는 자신이 등록된 스코프가 소멸(메모리 해제)될 때까지 유효하다. 할당된 메모리 공간은 더 이상 그 누구도 참조하지 않을 때 가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환된다.
💡 호이스팅은 스코프를 단위로 동작한다.
var
키워드로 선언한 전역 변수의 생명 주기는 전역 객체의 생명 주기와 일치한다.
전역 객체는 클라이언트 사이드 환경(브라우저)에서는 window
, 서버 사이드 환경(Node.js)에서는 global
객체를 의미한다. 브라우저 환경에서 var
키워드로 선언한 전역 변수는 전역 객체 window
의 프로퍼티가 되어 웹페이지를 닫을 때까지 유효하다.
var
, let
, const
차이점var
키워드로 선언한 변수는 중복 선언이 가능하다. 이때 중복되는 변수 선언문은 초기화문이 있으면 var 키워드가 없는 것처럼 동작하고 초기화문이 없으면 무시된다.
var x = 1;
var y = 1;
var x = 100; // var 키워드가 없는 것처럼 동작한다.
var y; // 무시된다.
console.log(x); // 100
console.log(y); // 1
let
키워드로 중복 선언하면 문법 에러(SyntaxError
)가 발생한다.
var
키워드로 선언한 변수는 선언과 초기화가 한번에 진행된다. 선언 단계에서 스코프에 변수 식별자를 등록해 자바스크립트 엔진에 변수의 존재를 알리고(선언), undefined
로 변수를 초기화한다.
→ 변수 선언문 이전에 변수에 접근해도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않고, undefined
를 반환한다.
let
키워드로 선언한 변수는 선언과 초기화가 분리되어 진행된다. 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
→ 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조 에러(ReferenceError
)가 발생한다.
TDZ(Temporal Dead Zone)
: 스코프의 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간
const
키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다.
var
또는 let
키워드로 선언한 변수는 재할당이 자유로우나 const
키워드로 선언한 변수는 재할당이 금지된다.var
키워드로 선언한 변수는 함수 레벨 스코프를 따른다.let
키워드로 선언한 변수는 블록 레벨 스코프를 따른다.var
키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 되지만 let
, const
키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다. let
, const
전역 변수는 전역 렉시컬 환경의 선언적 환경 레코드 내에 존재하게 된다.