본문으로 바로가기

호이스팅이란

호이스팅이란 함수안에 있는 선언이 끌어올려저 함수의 유효범위 내의 최상단에 선언되는 현상을 말한다. 여기서 유효범위란 함수 블록 내부를 의미한다.

function intro() {
	# 함수의 {} 태그 내부를 유효범위이라고 한다.
}

호이스팅은 함수가 실행되기 전에 변수값, 선언을 모아 유효범위의 최상단안에 선언하며 이는 자바스크립트 파서가 함수가 실행되기 전 검토하는 단계에서 실행된다. 이 과정에서 실제로 코드가 위로 끌여올려지는것은 아니며 자바스크립트 파서에서 내부적으로 끌어올리는 작업을 처리하며 실 코드에는 영향이 가지 않는다.

호이스팅의 적용 대상

호이스팅은 var 변수 선언과 함수 선언문에서만 발생하며 함수 할당이나 let/const 변수에서는 발생하지 않는다.

var name = 'john' 호이스팅 발생
let name = 'john' 호이스팅 미발생
function printName() { ... } 호이스팅 발생
var printName = function() { ... } 호이스팅 미발생

var변수 vs let/const 변수

console.log('hi');
var name = 'john'; // var 변수 
let name2 = 'clever'; // let 변수
/* 호이스팅 결과 */
var name; // 호이스팅 발생 - 선언
console.log('hi');
name = 'john'; // 할당
let name2 = 'clever'; // 호이스팅 미발생

함수선언문 vs 함수표현식

func();
func2();

function func() { // 함수선언문
  console.log('hi');
}
var func2 = function() { // 함수표현식
  console.log('hello');
}
/* 호이스팅 결과 */
var func2; // 호이스팅 발생 - 선언

function func() { // 호이스팅 발생 - 함수선언문
  console.log('hi');
}

func(); // [통과] - 호이스팅으로 인해 선언된 함수임
func2(); // [에러발생] - 선언되지 않은 함수임

func2 = function() { 
  console.log('hello');
}

함수선언문과 함수표현식에서의 호이스팅

함수선언문에서의 호이스팅

function printName(firstname) { // 함수선언문 
  var result = bind(); // 변수선언 및 함수할당
  console.log(typeof bind); // [출력] - function
  console.log("name: " + result); // [출력] - name: Traver"

  function bind() { // 함수선언문 
      return "Traver";
  }
}

printName();
/* 호이스팅 결과 */
function printName(firstname) { 
  var result; // 호이스팅 발생 - 선언

  function bind() { // 호이스팅 발생 - 함수선언문
      return "Traver";
  }

  result = bind(); // 함수 할당
  console.log(typeof bind); // [출력] - function
  console.log("name: " + result); // [출력] - name: Traver"
}

printName();

위의 예제에서는 bind()가 선언되기보다 먼저 var resultbind()함수를 할당하고 있지만 호이스팅이 발생함으로 인해 console.log()보다 bind() 선언이 우선되었기 때문에 오류 없이 코드가 실행된다.

함수표현식에서의 호이스팅

함수선언문과 달리 함수표현식에서는 변수 및 함수의 선언 순서에 따라서 오류가 발생할 수 있다. 이는 함수표현식에서는 선언과 할당의 분리가 일어나기 때문인데 함수표현식의 선언이 호출보다 아래에 있을 경우에 코드가 정상적으로 작동하지 않게 된다. 아래 예제를 보도록 하겠다.

function printName(firstname) {
  console.log(bind); // [출력] - undifined
  var result = bind(); // [오류발생]
  console.log("name: " + result);

  var bind = function() { // 함수표현식 
      return "bind value";
  }
}
printName();
/* 호이스팅 싫행 */
function printName(firstname) { 
    var bind; // 호이스팅 발생 - 선언

    console.log(bind); // [출력] - undifined
    var result = bind(); // [오류발생] - "bind is not function"
    console.log("name: " + result);

    bind = function() { 
        return "bind value";
    }
}
printName();

여기서 var bind는 아직 함수가 할당되지 않았기 때문에 이를 함수처럼 사용하려고 하면 "bind is not function"이라는 오류 메시지가 나온다. 이와같이 함수선언문과 달리 함수표현식은 호이스팅이 발생하지 않기 때문에 함수선언문처럼 함수 선언 전에 변수에 할당해 사용할 수 없다.

호이스팅 우선순위

자바스크립트 파서는 함수보다 변수를 더 우위로 판단하여 최상단에 위치시킨다.

var myName = "hi";

function myName() {
    console.log("discord");
}
function yourName() {
    console.log("master");
}

var yourName = "bye";

console.log(typeof myName);
console.log(typeof yourName);
/* 호이스팅 실행 */
// 1. 변수값 선언
var myName;
var yourName;

// 2. 함수선언문
function myName() {
    console.log("discord");
}
function yourName() {
    console.log("master");
}

// 3. 변수값 할당
myName = "hi";
yourName = "bye";

console.log(typeof myName); // [출력] - "string"
console.log(typeof yourName); // [출력] - "string"

호이스팅을 사용할때 유의할 점

이처럼 호이스팅은 변수 선언과 함수 선언을 순서에 구애받지 않고 자유롭게 할 수 있다는 장점이 있지만 함수표현식과 같은 예외도 있기 때문에 신중히 사용해야만 한다. 호이스팅만 믿고 중구난방으로 코드를 작성하기보다 처음부터 코드의 가독성과 유지보수를 고려해 개발하여 호이스팅이 발생하지 않도록 하는것이 최선이다. 호이스팅이 발생하는것을 방지하기 위해서는 다음과 같은 조치방법이 있다.

 

  • 변수와 함수를 가급적 유효범위의 상단부에서 선언한다
  • 변수를 먼저 선언한 다음 함수를 선언한다
  • var대신 let/const를 사용한다

ES6에서 지원하는 let/const는 호이스팅이 발생하지 않기 때문에 이를 활용하면 호이스팅으로 인한 오류발생을 방지할 수 있다. 이제 호이스팅이 발생하는 이유를 알았으니 어렵기만한 자바스크립트 개발을 조금이나마 수월하게 할 수 있을것 같다.