프론트엔드/JS
Hoisting
거북목을 가진 김기린
2022. 9. 18. 02:12
728x90
반응형
호이스팅(Hoisting)
- Javascript에서 호이스팅이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미
- var로 선언한 변수의 경우 호이스팅시 undefined로 변수를 초기화 한다
- 반면 let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다
- 호이스팅은 ES6 이전의 표준 명세에서는 나타나지 않았음
- var변수와 함수 선언문에서만 호이스팅이 일어남
- 변수 선언이 함수 선언보다 위로 끌어 올려짐
- let/const 변수 선언 및 함수 표현식에서는 호이스팅 발생 X
- 그렇다면 함수 표현식보다 함수 선언문이 무조건 옳은 것인가?
- 일부 코딩 컨벤션에서는 함수 표현식을 권장하기도 한다.
- 결론적으로, 어떤 컨벤션을 갖던지 한 가지만 정해서 사용하는 것이 좋다.
- 그렇다면 함수 표현식보다 함수 선언문이 무조건 옳은 것인가?
- 함수 선언문 예시
function foo(){ console.log("hello"); }
- 함수 표현식 예시
var foo = function(){ console.log("hello"); }
호이스팅 예시
- 호이스팅의 경우 설명보단 예시코드를 통해서 이해하는 것이 좀 더 빠른 이해가 될 것 같음
- 함수를 먼저 선언하고 함수를 호출하는 경우
- 일반적인 상황
function catName(name) {
console.log("제 고양이의 이름은 " + name + "입니다");
}
catName("호랑이");
/*
결과: "제 고양이의 이름은 호랑이입니다"
*/
- 함수를 호출하고나서 함수를 선언하는 경우
- JS 함수는 실행되기전에 함수 안에 필요한 변수값들을 모두 모아 유효범위 최상단에 선언
- 실제로 코드가 끌어올려지는 건 아니며, JS Parser가 함수 실행 전 해당 함수를 한 번 훑으며 Parser 내부적으로 필요한 값들을 끌어올리는 것 → 실제 메모리에서는 변화가 없음
- 함수 안에 존재하는 변수/함수에 대한 정보를 기억하고 있다가 실행시킨다.
- 유효범위 : 함수 블록
{}
안에서 유효 - 즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것
- 함수 선언이 먼저 되고, 다시 처음부터 읽어와 catName을 호출한다고 이해하면 쉬움
- JS 함수는 실행되기전에 함수 안에 필요한 변수값들을 모두 모아 유효범위 최상단에 선언
catName("클로이");
function catName(name) {
console.log("제 고양이의 이름은 " + name + "입니다");
}
/*
결과: "제 고양이의 이름은 클로이입니다"
*/
- 함수 선언문에서의 호이스팅
/* 정상 출력 */
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(); // 함수 호출
- 함수 표현식에서의 호이스팅 - 1
- 함수 표현식의 선언이 호출보다 아래에 있는 경우(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
- 함수 표현식에서의 호이스팅 - 2
- 함수 표현식의 선언이 호출보다 아래에 있는 경우(let/const 변수에 할당) - ReferenceError
- 함수 선언문 VS 함수 표현식
- 변수에 할당도니 함수 표현식은 끌어 올려지지 않기 때문에 이때는 변수의 스코프 규칙을 그대로 따름
var foo2;
function foo() { // [Hoisting] 함수선언문
console.log("hello");
}
foo();
foo2(); // ERROR!!
foo2 = function() {
console.log("hello2");
}
- 변수 선언이 함수 선언보다 위로 끌어올려 짐
var myName = "hi"; function myName() { console.log("yuddomack"); } function yourName() { console.log("everyone"); } var yourName = "bye"; console.log(typeof myName); // string console.log(typeof yourName); // string
- 값이 할당되어 있지 않은 변수와 값이 할당되어 있는 변수에서의 호이스팅
- 값이 할당되어 있지 않는 변수의 경우, 함수 선언문이 변수를 덮어쓴다.
- 값이 할당되어 있는 변수의 경우, 변수가 함수 선언문을 덮어쓴다.
var myName = "Heee"; // 값 할당 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"
- 선언만 호이스팅 대상
- JS는 초기화를 제외한 선언만 호이스팅한다.
- num이라는 변수가 선언만 되었기에 호이스팅 됨 → 다시 처음부터 읽어와 console.log(num)은 에러가 나지 않음
console.log(num); // 호이스팅한 var 선언으로 인해 undefined 출력
var num; // 선언
num = 6; // 초기화
- 선언없이 초기화만 존재하는 경우
console.log(num); // ReferenceError
num = 6; // 초기화
호이스팅 사용시 주의사항
- 코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않도록 한다
- 호이스팅을 제대로 모르더라도 함수와 변수를 가급적 코드 상단부에서 선언하면, 호이스팅으로 인한 스코프 꼬임 현상은 방지할 수 있다.
- 변수 선언시 var이 아닌 let/const를 사용한다
- 그래도 var과 호이스팅을 이해하는 이유는?
- ES6문법으로 짜여진 코드만 보면 상관이 없지만 레거시 코드들이 존재하고 이를 이해하기 위해서는 알아 두어야 하기 때문
- 그래도 var과 호이스팅을 이해하는 이유는?
728x90
반응형