Hoisting 의 개념
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 의미한다.
Hoisting이란?
자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다. 함수 블록 {} 안에서 유효하다. 함수 내에서 아래쪽에 존재하는 내용중 필요한 값들을 끌어올리는 것.
Hoisting의 대상
var 변수 선언과 함수 선언문에서만 hoisting이 일어난다.
var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
let/const 변수 선언과 함수표현식에서는 hoisting이 발생하지 않는다.
간단한 예시 (var 변수 vs let/const 변수)
console.log("hello");
var myname = "HEEE"; // var 변수
let myname2 = "HEEE2"; // let 변수 /** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
var myname; // [Hoisting] "선언"
console.log("hello");
myname = "HEEE"; // "할당"
let myname2 = "HEEE2"; // [Hoisting] 발생 X
간단한 예시 (함수선언문 vs 함수표현식)
foo();
foo2();function foo() { // 함수선언문
console.log("hello");
}
var foo2 = function() { // 함수표현식
console
}/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
var foo2; // [Hoisting] 함수표현식의 변수값 "선언"function foo() { // [Hoisting] 함수선언문
console.log("hello");
}foo();
foo2(); // ERROR!!foo2 = function() {
console.log("hello2");
}
호이스팅은 함수선언문과 함수표현식에서 서로 다르게 동작하기 때문에 주의해야 한다. 변수에 할당된 함수표현식은 끌어올려지지 않기 때문에 이때는 변수의 스코프 규칙을 그대로 따른다.
함수선언문에서의 호이스팅
함수선언문은 코드를 구현한 위치와 관계없이 자바스크립트의 특징인 호이스팅에 따라 브라우저가 자바스크립트를 해석할 때 맨 위로 끌어 올려진다.
/* 정상 출력 */
function printName(firstname) { // 함수선언문
var result = inner(); // "선언 및 할당"
console.log(typeof inner); // > "function"
console.log("name is " + result); // > "name is inner value"function inner() { // 함수선언문
return "inner value";
}
}printName(); // 함수 호출 /** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
/* 정상 출력 */
function printName(firstname) {
var result; // [Hoisting] var 변수 "선언"function inner() { // [Hoisting] 함수선언문
return "inner value";
}result = inner(); // "할당"
console.log(typeof inner); // > "function"
console.log("name is " + result); // > "name is inner value"
}printName();
즉, 해당 예제에서는 함수선언문이 아래에 있어도 printName 함수 내에서 inner를 function으로 인식하기 때문에 오류가 발생하지 않는다.
함수표현식에서의 호이스팅
함수표현식에서는 선언과 할당의 분리가 발생하기 때문에 함수 표현식은 함수선언문과 달리 선언과 호출 순서에 따라서 정상적으로 함수가 실행되지 않을 수 있다.
- 함수표현식의 선언이 호출보다 위에 있는 경우 — 정상 출력
/* 정상 */
function printName(firstname) { // 함수선언문
var inner = function() { // 함수표현식
return "inner value";
}
var result = inner(); // 함수 "호출"
console.log("name is " + result);
}printName(); // > "name is inner value"/* 정상 */
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 - 위와 동일 --- */
function printName(firstname) {
var inner; // [Hoisting] 함수표현식의 변수값 "선언"
var result; // [Hoisting] var 변수값 "선언"inner = function() { // 함수표현식 "할당"
return "inner value";
}
result = inner(); // 함수 "호출"
console.log("name is " + result);
}printName(); // > "name is inner value"
2. 함수표현식의 선언이 호출보다 아래에 있는 경우 (var 변수에 할당) — TypeError
/* 오류 */
function printName(firstname) { // 함수선언문
console.log(inner); // > "undefined": 선언은 되어 있지만 값이 할당되어있지 않은 경우
var result = inner(); // ERROR!!
console.log("name is " + result);var inner = function() { // 함수표현식
return "inner value";
}
}
printName(); // > TypeError: inner is not a function
/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 --- */
/* 오류 */
function printName(firstname) {
var inner; // [Hoisting] 함수표현식의 변수값 "선언"console.log(inner); // > "undefined"
var result = inner(); // ERROR!!
console.log("name is " + result);inner = function() {
return "inner value";
}
}
printName(); // > TypeError: inner is not a function
3. 함수표현식의 선언이 호출보다 아래에 있는 경우 (const/let 변수에 할당) — ReferenceError
/* 오류 */
function printName(firstname) { // 함수선언문
console.log(inner); // ERROR!!
let result = inner();
console.log("name is " + result);let inner = function() { // 함수표현식
return "inner value";
}
}
printName(); // > ReferenceError: inner is not defined
let/const의 경우, 호이스팅이 일어나지 않기 때문에 위의 예시 그대로 이해하면 된다.
- 함수표현식보다 함수선언문을 더 자주 사용하지만, 어떤 코딩컨벤션에서는 함수표현식을 권장하기도 한다. 즉, 어떤 컨벤션을 갖던지 한가지만 정해서 사용하는 게 좋다.
호이스팅 우선순위
- 변수 선언이 함수 선언보다 위로 끌어올려진다.
var myName = "hi";function myName() {
console.log("yuddomack");
}
function yourName() {
console.log("everyone");
}var yourName = "bye";console.log(typeof myName);
console.log(typeof yourName);/** --- JS Parser 내부의 호이스팅(Hoisting)의 결과 --- */
// 1. [Hoisting] 변수값 선언
var myName;
var yourName;// 2. [Hoisting] 함수선언문
function myName() {
console.log("yuddomack");
}
function yourName() {
console.log("everyone");
}// 3. 변수값 할당
myName = "hi";
yourName = "bye";console.log(typeof myName); // > "string"
console.log(typeof yourName); // > "string"
- 값이 할당되어 있지 않은 변수와 값이 할당되어 있는 변수에서의 호이스팅
var myName = "Heee"; // 값 할당
var yourName; // 값 할당 Xfunction myName() { // 같은 이름의 함수 선언
console.log("myName Function");
}
function yourName() { // 같은 이름의 함수 선언
console.log("yourName Function");
}console.log(typeof myName); // > "string"
console.log(typeof yourName); // > "function"
- 값이 할당되어 있지 않은 변수의 경우, 함수선언문이 변수를 덮어쓴다.
- 값이 할당되어 있는 변수의 경우, 변수가 함수선언문을 덮어쓴다.