참고한 자료
MDN
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Grammar_and_types
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let#%EC%8B%9C%EA%B0%84%EC%83%81_%EC%82%AC%EA%B0%81%EC%A7%80%EB%8C%80
모던 자바스크립트 Deep Dive
https://www.digitalocean.com/community/tutorials/understanding-hoisting-in-javascript
JS 엔진은 코드를 읽어 올 때,모든 변수를 스코프의 최상단으로 끌어올려 선언 한 뒤 런타임을 작동시킨다.
선언이 되었지만 아직 런타임이 동작하지 않아 할당되지 않은 변수의 초기값은 undefined로 초기화되고 만약 변수를 할당하기 전에 이 변수값을 콘솔로그에 불러왔다면, undefined라는 문구를 보게 될 것이다. 이것은 변수가 이미 선언되었지만 할당되지 않은 초기값을 불러왔다는 의미가 된다.
이를 호이스팅이라 부르고, JS는 let, function, class, const등의 모든 식별자를 호이스팅 하는 성질을 가졌다.
console.log(hoist); // Output: undefined
var hoist = 'The variable has been hoisted.';
이것이 함수나,변수를 런타임에서 직접 동작시키기 전에도 불러올 수 있는 이유이다.
이처럼, 식별자는 호이스팅 되어 초기값을 가져오는데, 변수가 선언과정에서 초기화 되기 전, TDZ(Temporal Dead Zone)동안에 불러와진 변수에 대해서는 ReferenceError
를 반환한다.
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}
var
의 경우에는 함수스코프를 제외한 스코프에 상관없이 변수를 호출할 수 있다는 기가막힌 단점이 있었지만,
ES6에 추가된 문법 let
과 const
의 경우에는 변수가 선언된 자리에 블록스코프가 적용되어 변수의 재할당의 문제에서 자유롭다는 장점이 생겼다. 이에 따라 let
과 const
의 경우에는 실제 런타임에서 선언되기 전에 변수를 불러오면 referrenceError를 던져준다는 특징이 있다.
함수 호이스팅은 변수호이스팅과 달리 선언즉시 함수객체가 생성되기 때문에 할당에 관여하지 않고 상단으로 호이스팅이 가능하다.
이 말은 선언된 함수를 그 위치에 상관없이 불러와 그 값을 불러오는게 가능하다는 의미이다.
하지만 여기에도 예외가 있는데, 함수표현식의 경우에는 선언과정에서 함수호이스팅이 아닌, 변수호이스팅이 작동하기 때문에, 런타임이전에는 값을 불러올 수 없다.
expression(); // Ouput: TypeError: expression is not a function
let expression = function hoisting() {
console.log('Will this work?');
};