console.log(a);
var a;
이 코드를 보고, 처음엔 당연히 에러가 나겠지 하고 생각했지만 아니었다!
자바스크립트에는 "호이스팅"이라는 특징이 있는데, 이 때문에 코드가 동작한다.
실행 결과는?
=> undefined
자바스크립트를 배우면서 기존에 배웠던 언어들과 참 다르다는 것을 새삼 느낀다. 신기방기🤔
식별자 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 것!
자바스크립트에서는 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 시점, 즉 런타임이 아니라 그 이전단계에서 먼저 실행된다.
소스코드를 실행하기 위한 준비 단계인 평가 과정에서, 자바스크립트 엔진은 먼저 변수 선언을 포함한 모든 선언문을 소스코드에서 먼저 선언하고, 그 다음 나머지 소스코드를 한 줄씩 순차적으로 실행한다.
변수 선언 뿐 아니라, var, let, const, function, class 키워드를 사용해 선언하는 모든 식별자(변수, 함수, 클래스 등)은 호이스팅 된다.
선언문은 호이스팅되지만 값의 할당은 소스코드를 실행하는 시점, 런타임에 이루어진다.
따라서,
console.log(a);
var a = 1;
console.log(a);
가 있을 때, 결과는
undefined
1
이 된다.
다른 언어들과 비교했을 때 굉장히 특이하다고 생각해서 왜 이러는건지 궁금했다. 왜 굳이..?
이런 생각이 들었달까..?
찾아보니 자바스크립트 엔진의 동작 원리 때문이라고 한다.
자바스크립트 엔진은 소스코드를 평가 - 실행하는 2단계로 나누어 진행된다.
평가 과정에서 변수와 함수 식별자를 key로 해 실행 컨텍스트가 관리하는 환경에 등록하고 이 과정에서 value 값을 undefined로 초기화 해준다.
따라서 코드를 실행할 때는 이미 함수 선언문과 변수가 생성되어 있는 상태이기 때문에 어디서든 함수나 변수를 호출할 수 있는 것이다!
어떠한 장점이 있다기 보다는 자바스크립트의 특성, 동작 원리라고 생각하면 될 것 같다..😊
사실 이러한 호이스팅 때문에 실수할 여지가 늘어나기 때문에, var 보다는 es6에서 만들어진 let, const를 사용하기를 권장하고 있다.
let은 var과 같이 호이스팅 되지만, 선언문 위에 사용되면 에러가 난다!
변수를 선언할 때 let을 쓰면 참조 에러가 발생한다.
위에 써있듯이, var 키워드로 선언한 변수는 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계와 초기화 단계가 한번에 진행된다.
하지만 let 키워드로 선언한 변수는 선언 단계 와 초기화단계가 분리되어 진행된다. 즉 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
따라서 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조에러(Reference Error)가 나는 것이다! 스코프의 시작 지점 부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 일차적 사각지대 라고 부른다고 한다.🤓
console.log(a); // 참조 에러
let a;
console.log(a); // undefined
a = 1;
console.log(a); // 1
코드는 이런식으로 작동한다.
그렇다고 호이스팅이 발생하지 않는 것은 아니다!
let a = 0;
{
console.log(a); // 에러 발생!
let a = 1;
}
원래 호이스팅이 되지 않는다면 0이 출력되어야 맞지만, 에러가 발생한다!
결국 let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것 처럼 보이지만, 발생한다는 것!
이렇게 자바스크립트에만 있는 특별한 동작원리 호이스팅에 대해 알아보았다!