본문 바로가기
Developer/Javascript 해부학

[JavaScript] Hoisting 이란?

by 해적거북 2022. 1. 27.
728x90

poiemaWeb - 데이터 타입과 변수

poiemaWeb - let, const와 블록 레벨 스코프

JaeYeopHan - Interview_Question_for_Beginner


 

1. 서론

기본적으로 코드를 작성할 때 변수를 선언한 후에 사용을 하는데, 함수의 경우 선언을 하단에 작성하고 사용하는 작업을 상단에서 하는 경우가 있었다.

Hoisting에 대해서 모르는 경우 함수 표현식으로 작성하였을 때 원하는 대로 동작하는 않는 경험을 하게 된다.

이러한 문제점은 Hoisting 이란 개념을 통해 해결해 나갈 수 있다.

 

 

2. Hoisting

JavaScript Parser가 모든 선언을 유효 범위(scope) 최상단으로 끌어올려지는 것이다.

Hoisting 대상은 var, let, const, function, class 모두이다.

초기에는 let, const가 Hoisting 안되는 것으로 이해하였는데 좀 더 정확하게는 변수, 상수의 생성 진행이 어디까지 되는 것의 차이였다.

 

 

3. 변수의 생성

변수의 생성은 3단계로 이루어진다.

선언 단계 → 초기화 단계 → 할당 단계

var 변수 키워드는 Hoisiting 되었을 때 선언과 초기화 단계가 동시에 진행되고

let 변수 키워드는 Hoisting 되었을 때 선언 단계까지만 진행된다.

이러한 차이로 let 변수가 작성된 코드상으로 선언되기 이전에 호출되면 Error가 나는 것이다.

 

 

4. 변수의 Hoisting

먼저 변수의 동작을 구분하면 변수의 선언변수의 할당으로 구분할 수 있다.

또한 변수는 var, let을 사용하여 변수임을 선언한다.

(const는 상수를 뜻하기 때문에 선언과 함께 할당을 해야만 한다)

 

// 변수의 선언
var data1;
let data2;

// 변수의 할당
data1 = 'java';
data2 = 'script';

// 변수의 선언과 할당
var data3 = 'java';
let data4 = 'script';

 

 

이제 변수의 Hoisting을 알아보기 위해 아래 예시를 보면

var로 선언된 data1, data2는 undefined를 출력할 뿐, Error가 아니라고 한다.

반면에, let으로 선언된 data3, data4는 Error를 출력하고 있다

 

function test() {
    console.log(data1); // undefined
    console.log(data2); // undefined
    console.log(data3); // Uncaught ReferenceError
    console.log(data4); // Uncaught ReferenceError
    
    var data1;
    data1 = 'java';

    var data2 = 'script';

    let data3;
    data3 = 'JAVA';

    let data4 = 'SCRIPT';
}

// 예시코드와 동일하게 실행하면 data3의 Error때문에 data4의 콘솔출력을 실행하지 않는다
// 이해를 위해 코드를 모아서 작성한 것이므로 테스트 시 코드를 분리해서 실행하면 된다

 

위 예시에서 data1과 data2는 undefined로 출력하는 원인은 var 변수 생성이 할당단계가지 진행되었기 때문이다.

위 예시의 Hoisting 된 코드를 아래 작성하였다.

var 변수의 Hoisting으로 data1, data2의 변수가 선언되었지만 할당되기 전에 사용되기 때문에 콘솔에서 undefined가 출력되는 것이다.

따라서 var로 작성된 어떠한 변수에 value가 할당되지 않아서 Error가 아닌 Error에 빠질 수 있다.

하지만 이러한 현상을 개선하고자 ES6에서는 let이라는 변수 선언 방법이 생겼다.

 

function test() {
  // var 변수의 선언이 Hoisting 됨
  var data1;
  var data2;

  console.log(data1); // undefined
  console.log(data2); // undefined
  console.log(data3); // Uncaught ReferenceError
  console.log(data4); // Uncaught ReferenceError
    
  // var 변수의 선언부분만 빠짐
  data1 = 'java';

  data2 = 'script';

  let data3;
  data3 = 'JAVA';

  let data4 = 'SCRIPT';
}

// 예시코드와 동일하게 실행하면 data3의 Error때문에 data4의 콘솔출력을 실행하지 않는다
// 이해를 위해 코드를 모아서 작성한 것이므로 테스트 시 코드를 분리해서 실행하면 된다

 

 

5. 함수의 Hoisting

함수를 작성하는 방법은 함수 선언식함수 표현식이 있다.

함수 표현식의 변수 작성은 var이든 let이든 상관없다.

 

// 함수 선언식
function test() {
    var data = 'javascript';
    console.log(data);
}

// 함수 표현식
let test = function() {
    var data = 'javascript';
    console.log(data);
}

 

이제 함수의 Hoisting을 알아보기 위해 아래 예시를 보면

함수 선언식으로 작성하면 'javascript'를 출력하지만,

함수 표현식으로 작성하면 Error를 만나게 된다.

이는 함수 선언식으로 작성한 함수가 Hoisting 되어서 func1호출을 하기 전에 선언하기 때문이다.

 

그리고  함수 표현식으로 작성된 func2와 func3를 자세히보면

서로 다른 Error가 출력되는 걸 볼 수 있는데,

이는 var와 let의 차이 때문이다.

 

var로 작성된 함수표현식

var func2 변수가 선언은 되었지만 함수로 할당되지 않은 상태에서 호출하였기 때문에

TypeError가 나오고 이는 var 변수 생성이 할당단계가지 진행되었기 때문이다.

 

이와 다르게 let으로 작성된 함수표현식

let func3 변수가 초기화조차 되지 않은 상태에서 호출하였기때문에

ReferenceError가 나오고 이는 let 변수 생성이 선언단계까지 진행되었기 때문이다.

 

function test() {
    func1(); // javascript
    func2(); // Uncaught TypeError : func2 is not a function
    func3(); // Uncaught ReferenceError : func3 is not defined
    
    function func1() {
        console.log('javascript');
    }
    
    var func2 = function() {
        console.log('javascript');
    }
    
    let func3 = function() {
        console.log('javascript');
    }
}

// 예시코드와 동일하게 실행하면 func2의 Error때문에 func3가 실행하지 않는다
// 이해를 위해 코드를 모아서 작성한 것이므로 테스트 시 코드를 분리해서 실행하면 된다

 

 

6. 결론

변수의 생성과정함수 선언식의 Hoisting을 이해하고 작성한다면, 코드 가독성을 향상시키고 Error 아닌 Error를 방지할 수 있다.

또한 되도록 변수의 선언은 let을 이용하고, 함수 표현식으로 작성하는 것이 적절하다.

 

 


 

728x90

댓글