영어 사전에서 Hoist는 '들어(끌어)올리다'라는 의미를 가지고 있다.
그러면 자바스크립트에서 호이스팅이란 무엇을 의미할까?
MDN에 의하면 JavaScript에서 호이스팅이란,
인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.
즉, 변수의 선언과 초기화를 분리한 후, 함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 의미한다.
var로 선언한 변수의 경우에는 호이스팅 시 undefined로 변수를 초기화 한다.
반면, let과 const로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.
let과 const로 선언한 변수도 호이스팅 대상이지만, var와 달리 호이스팅 시 undefined로 변수를 초기화하지 않는다.
따라서, 변수의 초기화를 수행하기 전에 읽는 코드가 먼저 나타나면 예외가 발생한다.
// y만 호이스팅 대상
x = 1; // x 초기화. x를 선언하지 않은 경우 선언. 그러나 명령문에 var가 없으므로 호이스팅이 발생하지 않음
console.log(x + " " + y); // '1 undefined'
// JavaScript는 선언만 호이스팅하므로, 윗줄의 y는 undefined
var y = 2; // y를 선언하고 초기화
변수는 3단계에 걸쳐 생성된다.
1. 선언 단계
- 변수를 실행 컨텍스트의 변수 객체에 등록한다.
- 이 변수 객체는 스코프가 참조하는 대상이 된다.
2. 초기화 단계
- 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
- 이 단계에서 변수는 undefined로 초기화된다.
3. 할당 단계
- undefined로 초기화된 변수에 실제 값을 할당한다.
변수 호이스팅
1. var 키워드 변수
var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어진다.
즉, 스코프에 변수를 등록하고 → 선언 단계
변수를 위한 공간을 확보한 후에 undefined로 초기화한다. → 초기화 단계
따라서, 변수 선언문 이전에 변수에 접근해도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않고 undefined를 반환한다. 그 이후 변수 할당문에 도달하면 값이 할당된다. ▶ 이것이 변수 호이스팅!!!!!!!!!!
// 스코프의 선두에서 선언 단계와 초기화 단계가 실행된다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 있다.
console.log(foo); // undefined
var foo;
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
2. let/const 키워드 변수
let 키워드로 선언된 변수는 var 키워드로 선언된 변수와 달리 선언 단계와 초기화 단계가 분리되어 진행된다.
즉, 스코프에 변수를 등록하지만 → 선언 단계
초기화 단계는 변수 선언문에 도달했을 때 이루어진다.
초기화 이전에 변수에 접근하려고 하면 변수가 초기화 되지 않았기 때문에 참조 에러(ReferenceError)가 발생한다.
즉, 변수를 위한 메모리 공간이 아직 확보되지 않았기 때문에 스코프의 시작 지점부터 초기화 시작 지점(TDZ: 일시적 사각지대)까지는 변수를 참조할 수 없어서 참조 에러(ReferenceError)가 발생한다.
// 스코프의 선두에서 선언 단계가 실행된다.
// 아직 변수가 초기화(메모리 공간 확보와 undefined로 초기화)되지 않았다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined
let foo; // 변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); // undefined
foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1
let으로 선언된 변수는 호이스팅이 발생하지 않는 것처럼 없어보이지만,
호이스팅이 여전히 발생하기 때문에 참조 에러(ReferenceError)가 발생하는 것이다.
함수 호이스팅
1. function 키워드 함수
함수 선언문의 경우, 선언/초기화/할당 단계가 동시에 진행된다.
그래서 할당 전 호출해도 undefined가 아니라 함수 내용이 리턴된다.
// 함수 선언문
hoisted(); // logs "foo"
function hoisted() {
console.log("foo");
}
여기서 주의해야할 점은 함수 표현식은 호이스팅 되지 않는다는 것이다.
함수 표현식은 변수 호이스팅과 같이 런타임 이전에 해당 값을 undefined로 초기화만 시키고, 런타임에서 해당 함수 표현식이 할당되어 그 때 객체가 된다.
// 함수 표현식
notHoisted(); // TypeError: notHoisted is not a function
var notHoisted = function() {
console.log("bar");
};
참고
https://developer.mozilla.org/ko/docs/Glossary/Hoisting
https://poiemaweb.com/es6-block-scope
https://nuhends.tistory.com/111
https://www.howdy-mj.me/javascript/var-let-const
'기술 개발 > Javascript' 카테고리의 다른 글
정규표현식(Regex) (0) | 2023.02.08 |
---|---|
얕은 복사 vs 깊은 복사 (1) | 2023.01.12 |
async & await (0) | 2022.08.10 |
Promise (then, catch) (0) | 2022.08.09 |
Callback 함수 (0) | 2022.08.05 |