hoist
는 감아올리기
hoisting
은 감아올리기, 감아올림 그런 의미인데
자바스크립트 호이스팅이니까 자바스크립트에서 무언가를 감아올린다 라는 의미가 되겠다.
정확히는 자바스크립트가 실행될 때 자바스크립트 Parser
가 어떻게 자바스크립트 코드를 처리하는지에 대한 내용이다.
코드에서 변수, 함수의 "선언"들을 위로 올려서 처리한다.
- 변수, 함수의 선언들을 물리적으로(실제 코드)에서 감아올리지 않고,
Parser가 위로 올려서 처리한다는 것- 위에서 계속 강조하고 있지만 변수, 함수의 할당이 아닌 선언을 올려서 처리하는 것이다.
var one = 1;
console.log(one, two); // two is not defined
위의 예시에는 two
가 선언되어 있지 않으므로 당연히 에러가 뜬다.
var one = 1;
console.log(one, two); // 1 undefined
var two;
위의 예시에서도 코드 순서대로라면 two
를 선언하기 이전에 호출했으므로 에러가 나야하지만,
Javscript hoisting
이 작동해 two
의 선언을 우선적으로 실행했다. 그렇기 때문에 에러가 아닌 undefined
가 뜨는 것을 볼 수 있다.
var one = 1;
// 1 undefined 👌
// 1 2 ❌
console.log(one, two);
var two = 2;
위의 hoisting
을 봤다면 오해할 수 있는 부분이 있다.
위의 예시를 보면 콘솔에 one
, two
를 띄우는데
아!
JavaScript hoisting
으로two
를 먼저 선언하니까1 2
라고 나오지 않을까?
라고 생각할 수 있지만, 그건 변수의 할당과 선언을 헷갈린 것이다.
hoisting
은 변수의 선언만을 책임지기 때문에 위의 예시에서 볼 수 있듯 1 undefined
가 뜬다.
함수중에서도 함수 표현식은 hoisting
이 안되고, 함수 선언문은 hoisting
이 일어난다.
우리가 자주보는 함수 선언과 동일한 방법
// Hoisting 👌
function test1() {
// 구현
}
함수 선언문은 어디에 선언이 되었든 hoisting
이 일어난다.
// 함수안에서도 똑같이 hoisting이 일어난다는 것을 보여줌
/* hoisting 일어나기 전 */
function test() {
var func1 = innerFunc();
// innerFunc
console.log(func1);
function innerFunc() {
return 'innerFunc';
}
}
test();
/* hoisting 일어난 후 */
function test() {
// hoisting으로 선언 우선 호출
var func1;
// hoisting으로 우선 호출
function innerFunc() {
return 'innerFunc';
}
// 변수, 함수 "선언" 후에 할당
func1 = innerFunc();
// innerFunc
console.log(func1);
}
test();
함수를 변수에 할당 시켜놓은 것.
함수를 호출하는 것이 아님.
// Not hoisting ❌
// 익명 함수 표현식
var callFunc = function () {
// 구현
}
// 기명 함수 표현식
var callFunc = function test1 () {
// 구현
}
함수 표현식은 hoisting이 적용되지 않기 때문에 코드가 원하는대로
실행되지 않을 수 있다. (선언 오류가 날 수 있음)
/* hoisting 전 */
function test() {
// undefined
console.log(test1);
//TypeError: innerFunc is not a function
innerFunc();
var test1 = innerFunc();
var innerFunc = function() {
return 'innerFunc';
}
}
test();
/* hoisting 후 */
function test() {
// hoisting으로 선언 우선 호출
var test1;
var innerFunc;
// undefined
console.log(test1);
// TypeError: innerFunc is not a function
innerFunc();
test1 = innerFunc();
// 함수 표현식은 hoisting이 일어나지 않는다.
var innerFunc = function() {
return 'innerFunc';
}
}
test();
변수가 함수보다 우선 순위가 높음.
만약 같은 이름의 함수와 변수가 있다면, 변수의 값 할당에 따라 달라진다.
/* 변수가 우선 */
var result = 1;
function result() {
return 'function';
}
// 1
console.log(one);
/* 함수가 우선 */
// 변수에 값이 할당 되어있지 않음
var result;
function result() {
return 'function';
}
// function
console.log(one());
위에서 계속 var
를 사용했다.
var 는 es6 이전 문법이다.
let
과 const
는 es6에 나온 새로운 문법이다.
// undefined => hoisting으로 선언이 우선적으로 일어남
console.log(val);
var val = 1;
// throws a ReferenceError
console.log(val);
let val = 1;
이렇게 var
는 변수가 초기화 되기 전에 호출이 되면 undefined
로 에러가 뜨지 않는다. 그래서 예측이 되게 어렵다.
하지만 let
과 const
는 레퍼런스 오류가 뜨기 때문에 오류를 예측할 수 있게 된다. 이것이 장점이다.
위의 예시만 보면 let
과 const
는 hoisting
이 일어나지 않는 것 처럼 보인다. let / const
선언 변수는 호이스팅되지 않는 것이 아니다.
스코프에 진입할 때 변수가 만들어지고 TDZ(Temporal Dead Zone)
가 생성되지만, 코드 실행이 변수가 실제 있는 위치에 도달할 때까지 액세스할 수 없는 것이다.
let / const
변수가 선언된 시점에서 제어흐름은 TDZ
를 떠난 상태가 되며, 변수를 사용할 수 있게 된다.
var
변수의 경우 선언 단계 - 초기화 가 동시에 이루어지는 반면, let / const
변수의 경우 선언 단계와 초기화 단계가 나누어서 이루어진다.
let / const
변수의 선언 단계와 초기화 단계 사이를 일시적 사각 지대 (Temporal Dead Zone; TDZ)
라고 부른다.
실제 코드에서 let
변수의 선언 또는 const
변수의 선언 및 할당 (const 의 경우 선언과 동시에 값 할당이 되어야 한다.)이 나오기 전까지는 해당 변수는 TDZ에서 관리 한다고 생각하면 된다.
해당 코드가 나오기 전에 미리 사용을 하려고 할 경우 TDZ에서 ReferenceError
를 발생 시킨다.
https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html