Hoisting

midohree·2020년 7월 18일
0
post-thumbnail
post-custom-banner

호이스팅(Hoisting)

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

그러면.. let과 const는 hoisting이 될까 안될까?

console.log(name); // ReferenceError
let name = "midohree";

된다!!!
var 뿐만 아닌 let과 const키워드, 변수 선언이 가능한 function 또한 호이스팅 된다.
그런데 왜 출력 결과가 undefined가 아닌 ReferenceError일까..?

TDZ ☠️

TDZ(Temporal Dead Zone)

  • 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이 사용된 코드에 도착했을 때 이루어진다.

함수 호이스팅

함수또한 변수이기 때문에, 호이스팅이 가능하다!

함수 표현식(Function Expression)

  • 모든 변수 선언문에 호이스팅이 해당하기 때문에, 함수 표현식으로 작성하는 경우에는 항상 실행문위 위치와 함수를 대입하는 구문의 위치가 매우 중요하다.
d();

var d = function () {
  console.log("I'm inside function d");
};

d();

함수 선언식(Function Declaration)

  • 함수 선언식으로 작성된 함수의 경우에는 항상 최상위로 호이스팅되어 실행문의 순서가 중요하지 않아 편리하다.
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 가 출력된다. 🤓

post-custom-banner

0개의 댓글