호이스팅
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.
자바스크립트 함수는 실행되기 전에 함수 안에 필요한 변수값들을 모두 모아서 유효 범위의 최상단에 선언한다.
- 자바스크립트 Parser가 함수 실행 전 해당 함수를 한 번 훑는다.
- 함수 안에 존재하는 변수/함수선언에 대한 정보를 기억하고 있다가 실행시킨다.
- 유효 범위: 함수 블록 {} 안에서 유효
즉, 함수 내에서 아래쪽에 존재하는 내용 중 필요한 값들을 끌어올리는 것이다.
(코드를 실행하기 전 변수선언/함수선언을 해당 스코프의 최상단으로 끌어올리는 것이 아니며, 끌어 올려진 것 같은 현상을 말한다. 자바스크립트 Parser 내부적으로 끌어올려서 처리하는 것이다. 실제 메모리에서는 변화는 없다.)
이 호이스팅이라는 용어를 선언이 코드 실행 보다 먼저 메모리에 저장되는 과정으로 인한 현상을 호이스팅이라고 부른다는 것으로 이해하면 되겠다.
변수 생성 단계
자바스크립트 엔진에서 변수는 선언 → 초기화 → 할당을 거쳐 변수가 생성된다.
1단계: 선언 단계(Declaration phase)_예) var myValue
- 변수를 실행 컨텍스트의 변수 객체에 등록한다.
- 이 변수 객체는 스코프가 참조하는 대상이 된다.
2단계: 초기화 단계(Initialization phase)_예) myValue = 100
- 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
- 이 단계에서 변수는 undefined로 초기화 된다.
3단계: 할당 단계(Assignment phase)_ 예) alert(myValue)
- undefined로 초기화된 변수에 실제 값을 할당한다
호이스팅의 대상
var 변수 선언과 함수 선언문에서만 호이스팅이 일어난다.
var a를 상단으로 호이스팅했기 때문에 변수 선언 전에 console.log로 출력을 해도 에러가 발생하지 않고, undefined가 출력된다. 모든 선언(function, var, let, const, class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 Temporal Dead Zone 상태로 유지된다.console.log(a); // undefined var a = "A"; // var 변수 /* 호이스팅 된 코드 */ var a; console.log(a); a = "A";
자바 스크립트 엔진은 코드를 실행하기 전에 실행 컨텍스트에 등록된 변수 객체에 접근할 수 있다.
- var의 경우 변수 선언&초기화가 함께 진행되므로, 변수 객체 등록과 동시에 메모리 공간도 할당 받는다.
- 그렇기 때문에 메모리를 할당받은 상태이므로 호이스팅시 메모리 참조를 통해 변수 접근이 가능하다.
- let의 경우, 선언과 초기화를 각각 진행한다.
- 선언 단계에서 실행 컨텍스트에 등록은 했지만, 메모리를 할당받지 못해 접근이 불가능한 상태이다. 결국, 메모리를 할당받지 못해 참조할 메모리가 없으므로 ReferenceError가 발생한다.
- 변수는 선언된 위치에서 초기화하기 전까지 TDZ 안에 들어간다.(그래서 선언하기 전에 변수를 사용할 수 없음)
- TDZ(Temporal Dead Zone) : 일시적인 사각지대라는 뜻 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 말한다.
- 모든 선언(function, var, let, const 및 class)은 JavaScript에서 호이스팅되며, var 선언은 undefined로 초기화되지만 let 및 const 선언은 초기화되지 않은 상태로 유지된다. (선언에는 호이스팅이 발생하지만 초기화는 호이스팅 되지 않는다는 의미)
호이스팅 법칙
1. 매개변수 및 변수는 선언부를 호이스팅한다.
2. 함수 선언은 전체를 호이스팅한다.
함수 호이스팅
함수의 선언 역시 호이스팅의 대상으로 스코프 내에서 어떤 위치에서 함수 선언을 하든지 호출할 수 있다.
<함수 선언식>
sayName(); function sayName(){ console.log('yuddomack'); }
▼
function sayName(){ console.log('yuddomack'); } sayName();
함수 선언 역시 최상단으로 끌어올려지기 때문에 sayName()을 먼저 호출하고 함수 정의를 이후에 하여도 정상적으로 작동함
<함수 표현식>
sayName(); var sayName = function(){ console.log('yuddomack'); }
▼
var sayName; sayName(); sayName = function(){ console.log('yuddomack'); }
var sayName은 변수이기 때문에 '선언과 할당'의 분리가 발생한다. sayName이 선언되고 sayName()이 호출되지만 거기엔 아무것도 없습니다. 그 이후에 sayName에 함수가 정의되는 것
변수 '할당'이 함수 선언보다 우선 순위이고, 함수 선언이 변수 선언보다 우선 순위이다.(변수 할당>함수 선언> 변수 선언)
함수 선언문과 변수 할당문이 존재할경우, 변수 a선언 -> 함수 a선언 -> a에 값할당 순으로 실행된다.var myName = "hi"; function myName() { console.log("yuddomack"); } function yourName() { console.log("everyone"); } var yourName = "bye"; console.log(typeof myName); console.log(typeof yourName);
▼
var myName; var yourName; function myName() { console.log("yuddomack"); } function yourName() { console.log("everyone"); } myName = "hi"; yourName = "bye"; console.log(typeof myName); console.log(typeof yourName);
변수가 선언되고, 함수가 할당되지만 다시 String 값이 들어가게 됩니다.
💫
함수 선언문을 이용해서 코드를 작성하게된다면 그 함수 선언문이 나도 인지하지 못하는 사이에 호이스팅에 의해 위로 끌어올려져서 코드 전체에 영향을 끼치게 될 수 있다.
반면 표현식으로 작성한 경우에는 이 같은 위험과 무지에서 벗어날 수 있으므로 복잡하거나 전역 공간에서 이루어지는 코드 협업일수록 함수 표현식을 활용하는 습관이 중요하다.
'CS > 프로그래밍' 카테고리의 다른 글
forEach()와 map의 차이점 (0) | 2023.07.01 |
---|---|
객체 지향 프로그래밍 (0) | 2023.06.25 |
호이스팅 /Edited by.혜경 (0) | 2023.06.19 |
호이스팅 - 이도영 (0) | 2023.06.18 |
호이스팅 (0) | 2023.06.18 |