호이스팅
호이스팅이란 선언된 변수나 함수가 scope 내 최상위로 끌어올려지는 것(hoisting) 을 말한다.
변수의 호이스팅은 선언과 할당이 분리된다. 변수의 선언은 초기화나 할당 시에 발생하는 것이 아니라 최상위로 호출되지만, 할당은 호이스팅되지 않는다.
( e.i)
> 변수의 선언이 호이스팅된 경우
console.log(a); //undefined
var a;
> 변수의 할당은 호이스팅되지 않는다.
console.log(a); //undefined
var a = return true;
함수의 호이스팅은 함수의 선언이 최상위로 끌어올려지는 것을 말한다.
(함수의 선언은 함수 execution context가 있어야 에러 발생하지 않는다.
e.i, funciton(){}; //Uncaught SyntaxError: Unexpected token )
따라서 scope 내 마지막 함수 선언이 호이스팅된다.
e.i
function test1(){
return a();
function a(){
return true;
}
function a(){
return false;
}
}
console.log(test1()); //false
e.i
function test2(){
function a(){
return true;
}
return a();
function a(){
return false;
}
}
console.log(test1()); //false
단, 함수의 표현방식에 다르다는 점을 인식해야 한다. 앞서의 함수 기본식의 경우는 호이스팅이 되지만, 함수표현식의 경우는 변수의 정의 안에서 함수가 선언되기 때문에 함수식이기는 하지만 변수로 취급된다. 따라서 함수표현식의 경우에는, 변수의 호이스팅 방식이 적용된다. 즉, 함수기본식의 경우에는 호출문이 선언문 앞에 있어도 최상위로 호이스팅되지만, 함수표현식은 변수만 최상위로 할당되고 함수의 선언은 호이스팅되지 않는다.)
e,i)
function test2(){
return a();
var a = function(){
return true;
}
var a = function(){
return false;
}
}
console.log(test2()); //Uncaught TypeError: a is not a function
e.i)
function test3(){
var a =function(){
return true;
}
return a();
var a = function(){
return false;
}
}
console.log(test3()); //true
또한, 함수 선언은 변수 선언보다 우선시된다.
함수 선언의 호이스팅이 변수 할당을 덮고 호이스팅된다.
e.i)
var a;
console.log(a); //undefined
e.i),
var a;
console.log(a); //true
function a(){
return true;
}
3. 그러나 변수값이 할당된 후에는 변수의 선언이 함수의 선언보다 우선시되어 호이스팅된다.
e.i)
function test5(){
var a;
console.log(a); // function a(){ return true;}
var a = 1;
function a(){
return false;
}
console.log(a()); //1
}
이 2,3의 내용에서 알게 되는 것은 (1) 변수가 선언만 되었을 때는 변수의 호이스팅보다 함수의 호이스팅이 먼저 하게 된다는 점 (2) 변수가 할당까지 되었을 때는 함수의 선언을 덮어쓰고 변수의 선언이 호이스팅된다는 점이다.
여기서 나름대로의 결론을 내리자면, 함수의 선언을 할 때 호이스팅으로 인한 문제가 발생할 수 있다는 점에 주의해야한다. 함수의 선언 시에 함수표현식과 기본함수식의 경우는 호이스팅의 우선순위가 달라지기 때문에(함수표현식이 함수기본식을 덮어쓰고 호이스팅된다. ) 두 가지 함수표현식을 혼용해서 사용할 경우 혼란을 초래할 수 있다. 그러므로 같은 scope 내 함수표현에서는 "함수기본식만을 사용한다" 혹은 "함수표현식만을 사용한다" 는 등의 컨벤션을 정해야할 것이다.
또한, 함수명과 변수명이 동일해지면 도출될 의도치 않은 결과를 지양하기 위해 함수선언과 변수선언을 따로 관리해줘야 할 것이다.
function test5(){
var a;
console.log(a); // function a(){ return true;}
var a = function a(){
return true;
}
function a(){
return false;
}
console.log(a()); // function a(){ return true;}
}