자바스크립트에서는 변수를 선언하기 위해 var, let, const 키워드를 사용한다.
ES6 이전에는 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다.
var 키워드로 선언된 변수는 아래와 같은 특징이 있다.
for(var i=0; i<10; i++){
continue;
}
console.log(i) // 외부에서 참조 output : 10
console.log(name); //undefined
var name = "kim se hyun";
변수, 함수 등의 선언문이 해당 스코프의 상단으로 끌려 옮겨진 것처럼 동작하는 자바스크립트의 특징을 호이스팅이라 한다.
var로 선언된 변수는 호이스팅되어 선언하기 이전에 참조할 수 있다.(undefined)
var a = 1;
var a = 2 ;
의도하지 않은 변수값의 변경이 일어날 가능성이 크다.
var name = 'kim se hyun'; //전역 변수
console.log(name); // kim se hyun
{
var name = 'park se hyun'; //전역 변수
}
console.log(name); // park se hyun
var 키워드는 블록 레벨 스코프를 지원하지 않으므로 코드 블록{...} 내의 변수 name는 전역 변수이다. 그런데 이미 전역 변수 name이 선언되어 있다. var 키워드를 사용하여 선언한 변수는 중복 선언이 허용되므로 위의 코드는 문법적으로 아무런 문제가 없다.
단, 코드 블록 내의 변수 name는 전역 변수이기 때문에 전역에서 선언된 전역 변수 name의 값 'kim se hyun'을 새로운 값 'park se hyun'으로 재할당하여 덮어쓴다.
자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, class)을 호이스팅한다.
호이스팅이란, 변수나 함수 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다.
자바스크립트 엔진은 변수 선언을 2단계에 거쳐 수행한다.
var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 동시에 진행된다.
즉, 스코프에 변수를 선언 하고 메모리에 변수를 위한 공간을 확보한 후,
자바스크립트 엔진에 의해 암묵적인 초기화(undefined)가 자동으로 수행된다.
따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다. 다만, undefined를 반환한다.
이후 변수 할당문을 만나면 비로소 값이 할당된다.
이러한 현상을 변수 호이스팅(Variable Hoisting)이라 한다.
console.log(name); //선언문이 호이스팅 되었고, undefined로 암묵적인 초기화가 되어 에러가 발생하지 않는다.
var name = "kim se hyun";
console.log(name); //kim se hyun
하지만 var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러가 발생한다.
let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행되기 때문이다.
즉, 스코프에 변수를 선언하지만 초기화 단계는 변수 선언문을 만났을 때 이루어진다.
초기화 이전에 변수에 접근하려고 하면 참조 에러(ReferenceError)가 발생한다.
이는 변수가 아직 초기화되지 않았기 때문이다.
질문 : let으로 선언된 변수는 호이스팅이 발생하지 않을까?
위 코드의 경우, 전역 변수 name의 값이 출력될 것 같지만 let 선언문도 여전히 호이스팅되기 때문에 참조 에러(ReferenceError)가 발생한다.
let으로 선언된 변수는 블록 레벨 스코프를 가지므로 코드 블록 내에서 선언된 변수 name은 지역 변수이다.
그리고 name이라는 변수는 해당 스코프에서 호이스팅되어 전역 변수 name의 값이 출력되지 않고 참조 에러가 발생한다.
(자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, class)을 호이스팅한다.)
자바스크립트 엔진은 코드를 실행하기 전에 먼저 소스코드를 평가하는 과정을 거치면서 코드를 실행하기 위한 준비를 한다.
이때 준비 단계인 소스코드 평가 과정에서 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문(변수, 함수, 클래스 등)을 코드 내에서 찾아 먼저 실행한다.
그리고 소스코드의 평가 과정이 끝나고 나면 그때서야 변수 선언을 포함한 모든 선언문을 제외하고 소스코드를 한 줄씩 순차적으로 실행한다.
즉 자바스크립트 엔진은 선언문이 소스코드의 어디에 위치해 있든 다른 코드보다 먼저 실행한다.
아래의 코드를 보면 선언문이 소스코드가 순차적으로 실행되는 런타임 이전 단계에서 먼저 실행된다는 것을 알 수 있다.
console.log(name); //undefined
var name = 'kim se hyun'
console.log(name); //'kim se hyun'
console.log(foo()) // 3
function foo(){
return 3;
}
이처럼 변수 선언문외에도 모든 선언문이 해당 스코프의 상단으로 끌어올려진 것 처럼 동작하는 자바스크립트의 특징을 호이스팅이라 한다.