반응형

자바스크립트 공부를 하거나 면접을 보다보면 호이스팅에 대해 설명을 하거나 이해를 요구할 때가 많다.

그렇기 때문에 호이스팅에 대해 완벽하게 이해를 하고 있어야 원활한 자바스크립트 사용을 할 수 있다.

 

1. 호이스팅이란?

변수나 함수를 스코프 범위 안에서 언제든지 사용할 수 있도록 하는 것을 말한다.

예시를 보면 위의 말이 어떤 내용인지 이해할 수 있다.

console.log(a);  // undefined

var a = 123;

위의 코드를 보면 console.log를 통해 a라는 변수를 불러왔는데 해당 구문 위에는 a변수 선언이 없었음에도 에러메시지가 뜨는 것이 아니라 undefined가 뜨는 것을 볼 수 있다.

var a;

console.log(a);

a = 123;

즉 실제 코드의 실행은 위의 소스와 같이 적용이 됐다는 것을 알 수 있다. a라는 변수 선언을 호이스팅하고 그 a를 console.log를 통해 불러왔으니 아직 할당 된 값이 없기 때문에 undefined가 노출이 되는 것이다.

[!] 호이스팅은 선언된 변수가 스코프 범위 내에서 최상단으로 이동해서 하단에 있는 영역에서 그 변수들을 사용할 수 있도록 해주는 것이라 이해하면 쉽다. (실제로 변수의 위치가 상단으로 이동하는 것은 아니다.)

 

하지만 변수 선언은 var만 있는 것이 아니라 let, const 변수 선언이 있다.

그리고 let과 const는 var와 같은 호이스팅의 형태를 가지고 있지 않다.

 

2. var 변수 호이스팅

위의 예시와 같이 var는 변수 선언을 스코프 내에서 호이스팅한다. (선언과 동시에 초기화)

그리고 var 변수 선언은 특징이 있는데 함수(function) 내부에서 선언한 변수는 지역변수로 호이스팅이 되지만

함수 외에 if문, for문, while문 등의 문법에서는 해당 구문 안에서 사용된 var 변수 선언들을 전역변수로 호이스팅 시켜버린다.

 

- 함수

function test(){
  var a = 123;
  console.log(a);
}

test();  // 123 출력
console.log(a);  // 에러

- for 문

for (var i = 0; i < 5; i++){
  console.log(i);
  // 1
  // 2
  // 3
  // 4
}

console.log(i); // 5

위 for문의 예시를 보면 for문 안에서 변수 i를 선언했지만 for문 밖에서 console.log를 통해 i를 호출했을 때 for문이 다 돈 후 숫자 5가 출력이 되는 것을 볼 수 있다. 즉 for문 밖에서도 for문 안에서 선언한 변수를 사용할 수 있다는 것을 알 수 있다.

 

함수를 제외한 모든 구문 및 환경에서 var로 선언한 변수는 변수 선언 자체를 최상단으로 다 올린다고 생각하면 된다. (실제로 변수들을 제일 위로 올리는 것은 아니다)

 

이처럼 함수 내부에서만 지역 변수로 사용이 되는 var 변수는

함수 레벨 스코프 변수이다.

3. let, const 변수 호이스팅

위에서 설명한 var 변수 선언과 let, const 변수 선언은 다르다. 예시를 보면 쉽게 알 수 있다.

console.log(a);  // 에러

let a = 123;

console.log(a); // 123

var였다면 위의 소스는 undefined가 출력이 됐을텐데 let으로 변수 a를 선언하면 위의 소스는 에러가 출력된다. 이게 let과 var의 호이스팅에 가장 큰 차이인데, var는 선언된 변수들을 함수를 제외하곤 호이스팅하여 모든 곳에서 사용할 수 있도록 하고 let은 변수가 선언된 위치에 도달했을 때 그 기점을 기준으로 변수를 초기화한다. const 변수도 동일한 특성을 가진다.

즉 해당 let, const 변수 선언 이후에서야 비로소 해당 변수 값을 사용할 수 있다는 뜻이다.

 

그렇다고 let이나 const가 호이스팅을 안하는 것은 아니다. 위와 같이 변수가 선언된 이후에야 그 변수를 사용할 수 있는 이유는 TDZ(Temporal Dead Zone) 영역의 특징 때문이다.

let과 const변수가 선언되기 이전에 내용들은 일시적으로 죽은 영역이 된다. 즉 사용할 수 없는 영역이 된다.

console.log(a);

//////////////// TDZ (let으로 선언한 변수 a를 사용할 수 없다)

let a = 123;

console.log(a); // 123

그리고 var와는 또 다른 특징이 있는데 var는 함수에서만 지역변수로 호이스팅되고 for, if문 과 같은 다른 구문에서는 전역 변수로 호이스팅이 되었었는데 let, const는 모든 구문에서 지역변수 단위로 호이스팅이 된다. 이를 블록 레벨 스코프라고 부른다.

각 {} 중괄호 안에 있는 블록 블록마다의 요소들에 각각의 지역 변수를 선언해준다는 뜻이다.

for(let i = 0; i < 5; i++){
  console.log(i);
}

console.log(i);  // 에러

var에서 예시로 봤던 for문을 예로 들면

for문 안에 let으로 변수 i를 선언하고 그 바깥에서 console.log로 i를 호출했을 때 for문 안에서 i를 선언했기 때문에 에러메시지가 뜨는 것을 알 수 있다.

 

만약 for문 바깥에서도 i를 사용하고 싶다면 let i 변수 선언을 for문 바깥에서 해주는 것도 방법이다.

let i;

for(i = 0; i < 5; i++){
  console.log(i);
}

console.log(i);  // 5

 

var, let, const 변수 선언에 대한 추가적인 설명은 하단 링크에도 작성해놓았다.

2020.06.03 - [Frontend/Javascript] - Javascript (자바스크립트) - 변수 선언 (var, let, const)

 

4. 함수 호이스팅

변수와 마찬가지로 함수도 호이스팅이 있다.

(단, 함수 선언문 형식으로 선언 된 함수만 해당한다. ex. function aa(){})

aa(); // 'test' 출력

function aa(){
  console.log('test');
}

위와 같이 코드를 작성한다 했을 때 aa 함수는 aa() 호출보다 아래쪽에 있어서 함수 실행이 안될 것 같지만

함수 호이스팅으로 인해 function aa(){} 부분이 스코프 내에서 언제든지 사용할 수 있게 되고 스코프 범위 안에서는 어디서든 함수를 호출하고 실행할 수 있다.

aa(); // 'test' 출력

function aa(){
  console.log('test');
  
  function bb(){
    console.log('test2');
  }
}

bb(); // 함수 내부에서 선언한 함수는 밖에서 사용할 수 없기 때문에 에러 출력
반응형

+ Recent posts