Hoist라는 영어 단어의 의미는?
Hoist : 들어올리다, 승강 장치
어떤 사물을 끌어올리는 장비를 일반적으로 Hoist라고 한다.
자바스크립트에서 우리가 사용하는 모든 변수 선언문(var, let, const, function, class)은 스코프 내에서 최상위로 Hoisting 된다.
console.log(name);
var name = "midohree";
// undefined
위 코드를 보면 에러가 나오지 않고 undefined
가 나온다. 실행시점에 호이스팅에 의해 var
변수가 아래와 같이 최상단에 선언되기 때문이다.
var name;
console.log(name);
name = "midohree";
아래의 예제는 어떨까?
console.log(foo); // undefined
var foo = 123;
console.log(foo); // 123
{
var foo = 456;
}
console.log(foo); // 456
위 예제 또한 foo가 선언되지 않았음에도 Error가 아닌 undefined
가 출력된다.
그럼 변수가 어떻게 생성되며, 호이스팅은 어떤 과정을 통해 이루어지는걸까?
변수는 3단계에 걸쳐 생성된다.
1. 선언 단계(Declaration phase)
- 변수 객체에 변수를 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 된다.
2. 초기화 단계(Initialization phase)
- 변수 객체에 등록된 변수를 메모리에 할당한다. 이 단계에서 변수는 undefined로 초기화 된다.
3. 할당 단계(Assignment phase)
- undefined로 초기화 된 변수에 실제값을 할당한다.
이러한 과정을 거쳐 위의 예제코드를 풀어놓으면 아래와 같다.
var foo;
console.log(foo); // undefined
foo = 123;
console.log(foo); // 123
{
var foo = 456; // 전역변수 재할당
}
console.log(foo); // 456
console.log(name); // ReferenceError
let name = "midohree";
된다!!!
var 뿐만 아닌 let과 const키워드, 변수 선언이 가능한 function 또한 호이스팅 된다.
그런데 왜 출력 결과가 undefined가 아닌 ReferenceError일까..?
var
를 이용하여 선언한 변수들이 undefined
로 초기화되어 시작되는 것과 다르게, let
을 이용하여 선언한 변수는 해당 선언문이 실행되기 전까지 초기값이 정해져있지 않다. 초기값이 정해지지 않은 let
은 접근할 수 없기 때문에 ReferenceError
가 발생한다.
function sayHi() {
console.log(name);
console.log(age);
var name = "midohree";
let age = 10;
}
sayHi();
무엇이 출력될까?
정답은 undefined와 ReferenceError이다.
위 코드는 아래와 같습니다.
function sayHi() {
var name;
let age;
console.log(name);
console.log(age);
name = "midohree";
age = 10;
}
sayHi();
var
키워드를 사용한 name
변수는 undefined
를 기본값으로 호이스팅한다. name
변수를 출력하려는 줄에서 아직 변수를 정의하고 있지 않기 때문에 undefined
가 출력된다.
하지만 let
키워드(또한 const
)는 호이스팅 되지만 초기화되지 않는다. 이들을 선언(초기화)하는 줄 전에는 접근 할 수 없다. 이를 "일시적 사각지대" 라고 부른다. 선언 되기 전 변수에 접근하려고 하면, JavaScript는 ReferenceError
를 출력한다.
정리
- 변수는 선언단계 👉 초기화단계 👉 할당단계 총 3단계의 과정을 통해 생성된다.
var
키워드로 변수를 만들 경우, 선언과 초기화단계가 동시에 이루어진다. 초기화는undefined
로 자동 할당되기 때문에.- 하지만
let
키워드는 선언단계와 초기화 단계가 분리되어 진행된다. 초기화단계가 실제let
이 사용된 코드에 도착했을 때 이루어진다.
함수또한 변수이기 때문에, 호이스팅이 가능하다!
d();
var d = function () {
console.log("I'm inside function d");
};
d();
j();
function j () {
console.log("j");
};
j();
아래는 내가 헷갈렸던 예제이다.
var x = 1;
function foo () {
if (x > 1) {
var x = 2;
}
console.log(x); // ???
}
foo();
if문이 성립하지 않아 전역변수 x의 값을 출력할거라고 예상하였지만 정답은 undefined
이다.
왜?.. 호이스팅 단계를 다시 생각해보면 이 코드는 아래와 같다.
var x = 1;
function foo () {
var x;
if (x > 1) {
x = 2;
}
console.log(x);
}
foo();
var x = 2
에서 변수 선언이 최상위로 끌어 올라갔다. function foo
도 새로운 변수이기때문에 이를 벗어나진 못하고 foo함수 내부의 최상위로 올라갔다. var
키워드는 선언과 동시에 undefined
가 자동으로 초기화되어 할당된다. 그래서 정답은 undefined
가 출력된다. 🤓