본문 바로가기

Learning/Javascript

호이스팅(hoisting)

여러 강좌들을 보다 보면 자주 접하는 용어인 호이스팅

호이스팅은 변수와 함수의 선언을 가장 상단으로 올린다는 의미이다.

 

딱 여기까지만 생각하고 살다가 즉시실행함수(IIFE)에 대해보는 중 호이스팅을 다시 생각하는 계기가 되어

블로그에 남길려고 한다.

 

일반적으로 내가 알았던 호이스팅의 의미는 함수와 변수의 선언을 가장 상단으로 올린다. 이다.

foo();

function foo(){
  console.log('foo');
}

결과는 콘솔에 foo가 찍힐 것이다.

그럼 아래는 어떻게 될까?

foo();

var foo = () => console.log('foo');
//var foo = function(){console.log('foo')};

우리는 Uncaught TypeError: foo2 is not a function 와 같은 에러를 볼 수 있을 것이다.

호이스팅이 함수와 변수의 선언을 올리는것 아니였어? 라고 생각 하였다 나는.....

 

호이스팅의 설명은 맞다. 다만 내가 이해를 못한 거였다.

호이스팅은 함수와 변수의 선언을 올리는것 이다.

 

위의 코드를 호이스팅이 된 식으로 표현하면 아래와 같다.

var foo; // 변수의 선언이 호이스팅 됨

foo();

foo = () => console.log('foo');

foo는 호이스팅으로 상단으로 선언이 되지만 값의 할당은 여전히 그 자리를 차지 한다.

그래서 foo()를 호출하면 함수형이 아니라고 에러를 보내는 것이다.

 

변수 역시 마찬가지이다.

console.log(foo);

var foo = 1;

console.log(foo);

첫번째 console.log에 찍히는 값은 undefind 이다.

var foo;가 호이스팅으로 가장 위에 선언이 되면 첫번째 콘솔에 변수는 있으나 값은 없어 undefind가 출력되고

다음 1을 받아서 다음 로그에는 1이 찍힌다.

 

foo();

var foo = () => {
  console.log('step1 : ', a);
  a = 1;
  console.log('step2 : ', a);
}

var a = 3;

foo();

이경우는 어떻게 될까?

..

..

..

그러하다 실행이 되지 않는다.

var foo와 var a가 호이스팅이 되어 상단으로 올라가지만

foo(); 에서 값을 받기 전이기에 함수가 아니라고 타입에러가 발생한다.

훗...

var foo = () => {
  console.log('step1 : ', a);
  a = 1;
  console.log('step2 : ', a);
}

foo();

var a = 3;

console.log('step3 : ', a);

var a의 선언을 위로 호이스팅 하고

foo가 실행이 되어 

첫 stop1에는 a변수가 이미 호이스팅 되어 선언이 되어 있으니

값이 없다고 undefind를 출력 할것 이다.

다음 a에 1을 대입하고 

stop2는 1을 출력

그리고 foo함수는 종료 되고

a에 3을 대입 한다.

마지막으로 stop3에는 3을 출력

 

지금까지 적은 내용은 한줄로

호이스팅은 함수와 변수의 선언을 올리는것 이다.

끝.

한줄이지만 우리는 선언을 까먹으면 안된다.

 

호이스팅으로 선언이 올라가지만 값을 할당하는 부분은 올라가지 않는다라고 계속 적었다.

그럼 아래는 어떻게 될까???

function foo(a){
  console.log('step1 : ',a);
  xoo();
  var a = 1;
  function xoo(){
    a++;
    console.log('step2 : ',a);
  }
  console.log('step3 : ',a);
}

foo(2);

자바스크립트는 먼저 호이스팅을 하고 다시 실행을 한다.

var a를 호이스팅 하지만 이미 함수가 가진 인자에 a가 있어

최종적으로는 아래와 같은 모습으로 실행이 될것이다.

function foo(a){
  function xoo(){
    a++;
    console.log('step2 : ',a);
  }
  console.log('step1 : ',a);
  xoo();
  a = 1;
  console.log('step3 : ',a);
}

foo(2);

 

만약 위의 경우 var a = 1; 을 하지 않고 let a = 1; 을 사용하면 어떻게 될까?

브라우저는 a의 변수가 충돌이 난다고 오류를 보낸다.

 

고로 ie11을 사용하지 않는다면 let 선언을 쓰자. ㅎ