[JavaScript] 호이스팅

혜린·2022년 7월 25일
1

JavaScript

목록 보기
15/21
post-thumbnail

호이스팅이란?


🐲 용어 이해하기

호이스팅이란 선언된 변수, 함수의 선언부를 스코프에 따라 최상단으로 끌어올리는 개념입니다.
이는 hoisting 영단어 뜻 그대로임을 확인할 수 있습니다.

hoisting
(명사) 끌어 올리기, 들어올려 나르기 -네이버 영어사전 -

  • 하지만 이는 실제로 끌어올려지는 것이 아니라, JavaScript 내부적으로 끌어올려 처리됩니다.
  • 선언과 할당(초기화) 모두를 끌어올리는 것이 아닌, 선언부만 끌어올린다는 것을 눈여겨 보면 이해하기가 쉽습니다!
var number = 10;

위의 코드는 아래와 같이 나누어 볼 수 있는데요, 이 때 선언부에 해당되는 내용만 최상단으로 끌어올려줍니다.

var number; // *선언*
number = 10; // 할당(초기화)

🐲 호이스팅 예시

1. 예제

console.log(one); // undefined
var one = 1; 

위의 예제를 보면, 변수 one을 선언하기도 전에 console로 호출했으니 다른 언어라면 에러가 생기는 상황일 것입니다. 하지만 JavaScript는var로 선언한 변수의 경우, 호이스팅 시 undefined로 변수를 초기화합니다. 이에 따라, undefined를 출력하는 것을 확인할 수 있는데요! 이는 JavaScript의 호이스팅 으로 인해 생기는 현상입니다.

그렇다면 var로 변수를 선언한 경우, 호이스팅 시에 왜 undefined를 출력하는걸까요?


2. undefined가 뭐길래!

undefined : 아직 할당하지 않은 값

undefined란, ‘아직 할당하지 않은 값’을 의미합니다. 위의 예제 코드를 JavaScript 내부에서는 어떻게 해석하고 있는지 아래의 코드를 통해 살펴보면 왜 undefined가 출력되는지 알 수 있습니다.

// var one; 
console.log(one); // undefined
var one = 1;

var로 선언한 변수 one은 호이스팅이 되어 선언부만이 상단으로 끌어올려집니다.

따라서 첫 줄의 변수 one은 선언만 되어 있고 값은 할당되어있지 않은 상태인데요. 바로 이럴때의 변수 one은 JavaScript의 자료형 중 하나인 undefined인 상태라고 할 수 있습니다.


3. 함수 내부에서는 어떨까?

위의 예제와 같은 상황은 함수 내부에서도 동일하게 작용합니다.

function number(){
	console.log(one); 
	var one = 1;
	console.log(one); 
}
number();

// undefined
// 1

4. 변수 선언을 하지 않았다면?

호이스팅은 선언부만 끌어올린다는 것을 지금까지 설명했는데요, 그렇다면 변수 선언 없이 할당만한 상태라면 어떨까요?

console.log(one); // ReferenceError
one = 1; // 할당(초기화)

이때에는 호이스팅 발생하지 않고 ReferenceError가 뜨는 것을 확인할 수 있습니다.



호이스팅의 대상


var변수 선언과 함수 선언식일 때 호이스팅된다고 기억하고 있자!

1. 변수
변수 선언 방식 var, let, const 모두 호이스팅의 대상이긴 하지만 var로 선언한 변수만 위로 끌어올려집니다.

2. 함수
또한, 함수를 선언하는 방식으로 함수 선언식과 함수 표현식이 있는데 이 중, 함수 선언식에서만 호이스팅이 일어납니다.


🐲 var

var one = 1;을 보고 JavaScript는 선언부인 var one만을 최상단으로 끌어올립니다. 이에 따라, 선언은 되어있지만 할당된 값이 없다는undefined를 출력하는 것을 확인할 수 있습니다.

// var one;
console.log(one); // undefined 출력
var one = 1;

🐲 letconst

1. 호이스팅의 대상?

앞서 말했듯, letconst 역시 JavaScript의 변수 선언 방식이므로 호이스팅의 대상이기는 합니다. 하지만 선언부가 끌어올려지지는 않고 Error가 나는 것을 확인할 수 있습니다. JavaScript 내부적으로 접근은 하지만 실제 끌어올려지지는 않는다는 것!

console.log(one); // ReferenceError 발생
let one = 1;

위의 코드는 실제 console창에서 아래와 같이 ReferenceError가 뜨는 것을 확인할 수 있어요.

ReferenceError : 존재하지 않는 변수를 참조했을 때 발생하는 오류


2. ReferenceError를 발생시키는 이유?

그렇다면 왜 letconst로 변수 선언시 ReferenceError가 발생하는 걸까요?

var로 선언한 변수의 경우, 호이스팅 시 undefined로 변수를 초기화합니다. 반면 let
과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않습니다.

📜 MDN
let 변수는 초기화하기 전에는 읽거나 쓸 수 없다. 초기화 전에 접근을 시도하면 ReferenceError가 발생한다. 변수 스코프의 맨 위에서 변수의 초기완료시점까지의 변수는 “시간상 사각지대”(TDZ; Temporal Dead Zone)에 들어간 변수라고 표현한다.


🐲 함수 선언식

JavasScript 함수 선언 방법으로는 함수 선언식과 함수 표현식이있습니다.

1. 함수 선언식

함수 선언식은 별도의 할당 명령 없이 function키워드를 이용해 함수명, 인자, 내부 코드 작성하는 방식으로, 호이스팅의 대상입니다.

sayHi(); // hi

function sayHi(){
	console.log("hi");
}

위와 같이, 함수 선언식으로 선언한 sayHi함수는 호이스팅의 대상이 되어 함수를 선언하기 전에 호출하여도 정상적으로 결과가 출력되는 것을 확인할 수 있습니다.


2. 함수 표현식

2-1. var

함수 표현식은 변수 안에 함수를 할당하는 형태로, 호이스팅의 대상이 아닙니다.

sayHi(); // TypeError 발생

var sayHi = function(){
	console.log("hi");
}

위 코드에서 sayHi함수는 함수 표현식으로 선언되어있습니다. 이 때, console창에 TypeError가 발생하는 것을 확인할 수 있는데요.

TypeError : 일반적으로 값이 기대하던 자료형이 아니라서 연산을 할 수 없을 때 발생하는 오류

함수 표현식은 호이스팅의 대상이 아니라고는 하는데... 그렇다면 왜 호이스팅되지 않는걸까요? 아까 변수 선언할 때에는 var로 선언한 변수가 호이스팅의 대상이라고 했는데 말이죠.

이 때, JavaScript의 내부 동작을 보면 쉽게 이해할 수 있습니다.

// var sayHi; // undefined
sayHi(); // sayHi는 함수 아닌데 왜 함수 호출해? 
var sayHi = function(){
	console.log("hi");
}
  1. var로 선언한 변수는 호이스팅이 발생해 선언부만 최상단으로 끌어올립니다. 이에 따라, JavaScript는 선언부인 var sayHi만을 끌어올리게 되죠. sayHi는 선언은 되어있지만 할당값이 없으므로 JavaScript 자료형 중undefined인 것을 알 수 있습니다.
  2. sayHi의 자료형이 undefined라고 알고 있던 JavaScript는 두번째 줄을 보고 당황합니다. sayHi를 함수로 호출하고 있기 때문이죠.
  3. JavaScript 자료형은 numberbigintstringbooleanundefinednullsymbolobject 로 8가지인데요. 여기서 함수는 object에 속합니다.
  4. 따라서 undefined자료형으로 생각하고 있던 변수를 함수로 호출하고 있기에 TypeError가 발생하게 되는 것입니다.

2-2. letconst

호이스팅 영향을 받지않는 let이나 const를 사용하면 ReferenceError가 발생합니다.

sayHi(); // ReferenceError

let sayHi = function(){
	console.log("hi");
}



장점과 단점


1. 장점

  • 함수가 선언되기도 전에 함수를 활용할 수 있기 때문에 코드를 유연하게 구성할 수 있습니다.

2. 단점

  • 호이스팅이 일어나면, 위에서 아래로 순차적으로 진행되는 것이 아니기 때문에 결과를 예측하기 비교적 어려워집니다.
  • 변수, 함수명이 같은 상태로 호이스팅이 발생하면 변수가 함수값을 덮어쓰게 될 수 있습니다.



느낀점


🤔 호이스팅의 영향을 최소화하자!
변수 선언으로는 constlet을 사용하는 것이 좋다는 의견이 압도적이지만, 함수 선언 방식은 의견이 분분하다는 것을 알게됐다. 코드를 유연하게 짜기 위해 함수 선언식을 사용하는 것이 좋다는 말이 있는가 하면, 호이스팅의 영향을 최소화하기 위해 함수 표현식을 사용하는 것이 좋다는 말도 있었기 때문이다.

따라서, 호이스팅이 무엇인지와 그 대상은 무엇인지를 정확히 인지하고 있는 것이 중요할 것이란 생각이 들었다. 그래야 왜 코드가 꼬였고 에러가 발생했는지를 보다 빠르게 찾을 수 있을 것 같다. 개인적으로는 함수를 선언할 때에도 코드가 순서대로 동작할 수 있도록 작성하여 호이스팅의 영향을 최소화하는 것이 효율적으로 보인다.


🤯 다른 사람에게 설명할 수 있어야 한다!
그동안 선언부만 끌어올린다는 개념이 참 와닿지 않아 호이스팅이 어렵게만 느껴졌었다. 하지만, 이번 위코드 사전스터디를 계기로 호이스팅을 자세히 공부하고 다른 사람에게 설명하며 참 도움이 많이 됐다. 내가 공부한 개념을 다른 사람이 들어도 알기 쉽게 설명할 수 있어야 비로소 내 것이 됨을 느꼈다. 혼자 이해하고 넘어가지 말고, 블로그를 통해서라도 설명하며 지식을 온전히 내 것으로 만들자!!!



참고


자바스크립트(JavaScript) - 호이스팅(Hoisting)
JS의 호이스팅과 var, let, const의 차이점
모던 JavaScript 튜토리얼

profile
FE Developer

0개의 댓글