...
자바스크립트 호이스팅(Hoisting)
자바스크립트에서 호이스팅(Hoisting)은 변수 선언과 함수 선언을 코드의 맨 위로 끌어올려지는 현상을 일컫는다. 그래서 개발자가 어느 라인 위치에 코드를 선언해도, 실행 되기전 코드가 최상단으로 끌어올려지고 실행되게 된다.
이러한 호이스팅이 발생하는 원인은 자바스크립트의 변수 생성(Instantiation)과 초기화(Initialization)의 작업이 분리돼서 진행되기 때문이다.
console.log(a()); // 'a'
console.log(b()); // Uncaught TypeError: b is not a function
console.log(c()); // Uncaught TypeError: b is not a function
function a() {
return 'a';
}
var b = function bb() {
return 'bb';
}
var c = function() {
return 'c';
}
위에 보이는 코드에서 a() 부터 실행 오류가 떠야 하지만 a는 출력이 된다. (b와 c는 오류)
왜냐하면 호이스팅에 의해서 실제 자바스크립트 컴파일은 이런식으로 이루어 지기 때문이다.
function a() {
return 'a';
}
var b;
var c; // 함수 선언은 위로 강제로 끌어져 올라온다. (호이스팅)
console.log(a());
console.log(b());
console.log(c());
b = function bb() {
return 'bb';
}
c = function() {
return 'c';
}
보는 바와 같이 함수 선언과 변수 선언이 위로 호이스팅 돼서 정의가 되었기 때문에 console.log(a()); 는 실행이 되었던 것이다. 그런데 b(), c()는 아직 변수 b와 c 안에 넣어지지 않은 형태이기 때문에, 함수 선언문이 아니라서 b와 c는 그냥 변수로 취급 때문에 실행 오류가 뜨는 것이다.
함수의 호이스팅
자바스크립트 함수를 정의하는 문법으로 함수 표현식과 함수 선언식 두 가지가 있다.
// 함수 선언식
function add(x, y) {
return x + y;
}
// 함수 표현식
const add = function(x, y) {
return x + y;
};
둘은 결국 함수를 만드는데 기본적으로 동일한 기능을 수행하지만, 함수 표현식은 함수를 변수에 할당하므로 유연성이 높다. 그리고 호이스팅이 강제적으로 되지 않아 개발자로 하여금 혼동을 주지 않게 한다.
함수 표현식 권장이유
함수 선언식의 사용 예제를 보자
console.log(add(2, 3));
function add(x, y) {
return x + y;
}
console.log(add(3, 4));
// >> 5
// >> 7
add(2, 3)은 아직 function add() 함수가 정의되지 않았음에도 불구하고 add() 함수를 호출하는 것이 가능하다. 왜냐하면 코드 해석 단계에서 호이스팅이 일어나 function add() 가 상단으로 끌어올려졌기 때문이다.
이러한 구조는 함수를 선언하기 전에 함수를 선언한 것이기 때문에 코드의 구조를 엉성하게 만들 수도 있다. 그래서 함수 표현식만을 사용하라고 권장하는 것이다.
console.log(add(2, 3)); // error
// 함수 표현식 형태로 add() 함수 정의
var add = function (x, y) {
return x + y;
}
console.log(add(3, 4)); // 7
처음의 add(2, 3) 함수는 실행되지 않는다. 왜냐하면 함수 표현식 형태로 add() 함수가 정의되어 있기 때문이다. 따라서 호이스팅이 일어나지 않는다.
그러나 함수 선언식과 함수 표현식 중 어느것이 정답인지는 개발자들 간에 이견이 분분하다. 왜냐하면 함수 자체는 코드 어느 라인에 선언하든, 함수 자체이기 때문에 그렇게 큰 문제가 되지 않기 때문이다.
변수의 호이스팅
함수 뿐만 아니라 변수 자체도 호이스팅이 일어난다. 단, 변수를 정의할때 var 키워드를 썼을때의 얘기이다.
var globalNum = 10; // globalNum을 전역 변수로 선언함.
function printNum() {
document.write(globalNum);
var globalNum = 20; // globalNum을 지역 변수로 선언함.
document.write(globalNum);
}
printNum();
/* 결과
undefined
20
*/
처음에 전역변수로 globalNum을 먼저 선언했음에 불구하고 첫번째 변수 호출 값은 undefined를 내놨다. 그 이유는 자바스크립트 내부에서는 함수 호이스팅에 의해 다음과 같이 코드가 변경되어 처리되기 때문이다.
var globalNum = 10;
function printNum() {
var globalNum; // 함수 호이스팅에 의해 변수의 선언 부분이 함수의 맨 처음 부분으로 이동됨.
document.write(globalNum);
globalNum = 20;
document.write(globalNum);
}
printNum();
이러한 특징 때문에 코드의 가독성을 해치거나, 예상치 못한 동작을 일으키기도 하므로 변수를 선언할때는 var 키워드는 절대 금지하고 ES6의 let 이나 const 키워드를 사용하는 것을 강력히 권장한다. 왜냐하면 let, const로 변수를 선언하면 블록 스코프를 가지게 되므로, 호이스팅이 발생하지 않기 때문이다.
# 참고자료
https://deftkang.tistory.com/17
https://web-front-end.tistory.com/23
https://velog.io/@surim014/JavaScript%EC%97%90%EC%84%9C%EC%9D%98-Hoisting%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.