호이스팅(Hoisting)의 개념
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.
자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
호이스팅의 대상
var 변수 선언과 함수선언문에서만 호이스팅이 일어난다.
- var 변수/함수의 선언만 위로 끌어 올려지며, 할당은 끌어 올려지지 않는다.
- let/const 변수 선언과 함수표현식에서는 호이스팅이 발생하지 않는다.
- 호이스팅은 함수선언문과 함수표현식에서 서로 다르게 동작하기 때문에 주의해야 한다.
foo(); foo2(); function foo(){ console.log("hello") } var foo2 = function(){ console.log("hello2"); } //hello //TypeError: foo2 is not a function
- 변수에 할당된 함수표현식은 끌어 올려지지 않기 때문에 이때는 변수의 스코프 규칙을 그대로 따른다.
var foo2; // 호이스팅. 함수표현식의 변수값 "선언" function foo() { 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 호이스팅 결과.
- 함수선언문이 아래에 있어도 printName 함수 내에서 inner를 function으로 인식하기 때문에 오류가 발생하지 않는다.
function printName(firstName){ var result; // 호이스팅. var 변수 "선언" function inner() { // 호이스팅. 함수선언문 return "inner value"; } result = inner(); // 할당 console.log(typeof inner); // "function" console.log("name is" + result); // "name is inner value" } printName();
함수표현식에서의 호이스팅
- 함수 표현식은 함수선언문과 달리 선언과 호출 순서에 따라서 정상적으로 함수가 실행되지 않을 수 있다. -> 함수 표현식에서는 선언과 할당의 분리가 발생한다.
- 함수표현식의 선언이 호출보다 위에 있는 경우 - 정상출력
function printName(firstname){ var inner = function(){ return "inner value"; } var result = inner(); console.log("name is" + result); } printName(); "name is inner value"
- JS Parser 내부 호이스팅 결과는 같다.
function printName(firstname){ var inner; var result; inner = function(){ return "inner value"; } result = inner(); console.log("name is " + result); } printName();
- 함수표현식의 선언이 호출보다 아래에 있는 경우 (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
호이스팅 결과
function printName(firstname){ var inner; // 호이스팅. 함수 표현식의 변수값 "선언" 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
- printName에서 "inner is not defined" 가 아니고 "inner is not a function" 이라는 TypeError가 나오는 이유? -> printName이 실행되는 순간 (호이스팅) inner는 "undefined"로 지정되기 때문에. inner가 undefined라는 것은 즉, 아직은 함수로 인식되지 않고 있다는 것을 의미한다.
- 함수 표현식의 선언이 호출보다 아래에 있는 경우. (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(); // RefereneceError : inner is not defined
- let/const의 경우 호이스팅이 일어나지 않는다.
- console.log(inner); 에서 inner에 대한 선언이 되어있지 않기 때문에, 이때는 "inner is not defined" 오류를 발생한다.
호이스팅 우선순위
같은 이름의 var 변수 선언과 함수 선언에서의 호이스팅
- 변수 선언이 함수 선언보다 위로 끌어올려진다.
var myname = "marvel"; function myName(){ console.log("superman"); } function yourName(){ console.log("batman"); } var yourName() = "ironman"; console.log(typeof myName); console.log(typeof yourName);
호이스팅 결과.
// 1. 호이스팅 변수값 선언. var myName; var yourName; // 2. 호이스팅 함수선언문 function myName(){ console.log("superman"); } function yourName(){ console.log("batman"); } // 3. 변수값 할당. myName = "marvel"; yourName = "ironman"; console.log(typeof myName); // "string" console.log(typeof yourName); // "string"
값이 할당되어 있지 않은 변수와 값이 할당되어 있는 변수에서의 호이스팅.
var myName = "ironman"; // 값 할당 var yourName; // 값 할당 X function myName(){ // 같은 이름의 함수 선언 console.log("myName Function") } function yourName(){ // 같은 이름의 함수 선언 console.log("yourName Function"); } console.log(typeof myName); // "string" console.log(typeof yourName); // "function"
- > 값이 할당되어 있지 않은 변수인 경우 , 함수선언문이 변수를 덮어쓴다. -> 값이 할당되어 있는 변수의 경우, 변수가 함수선언문을 덮어쓴다.
호이스팅 사용 시 주의 할 점
- 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 한다. -> 호이스팅을 제대로 모르더라도 함수와 변수를 가급적 코드 상단부에서 선언하면, 호이스팅으로 인한 스코프 꼬임 현상을 방지 할 수 있다. -> let/const를 사용하자.