변수 호이스팅
console.log(number);
var number;
위의 코드를 실행해보면 console.log(number); 는 어떤 값이 출력될까? 자바스크립트를 처음 접한다면 ‘당연히 에러가 발생하지 않을까?’ 라고 생각할 수 있다. 하지만 undefined 가 출력된다. 분명 자바스크립트의 소스코드도 여느 프로그래밍 언어와 마찬가지로 한줄씩 차례대로 실행되는데 어떻게 이게 가능한걸까?
바로 자바스크립트의 호이스팅에 의해 그렇다. 호이스팅에 대해 알아보고자 한다.
호이스팅(Hoisting)은 변수 또는 함수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징이다. 따라서 위의 코드를 살펴볼 때, 실제 동작 순서는 number 변수가 선언되고 나서 콘솔 코드가 실행되게 된다.
console.log(number); // 1번 로그
var number;
number = 10;
console.log(number); // 2번 로그
그렇다면 위의 코드는 어떨까? 이것 역시 1번 로그와 2번 로그 둘 다 변수가 값을 가지게 되어 10이 출력될까?
답은 1번 로그는 undefined, 2번 로그는 10이 출력된다. 왜 그럴까?
앞서 얘기한 호이스팅 개념은 “선언”에 대해서만 해당한다. 즉 10과 같은 값을 “할당”할 때는 호이스팅이 적용되지 않는다. 따라서 할당문은 런타임에 순차적으로 실행된다.
위의 내용을 이해한다면 아래의 예제 코드의 결과도 쉽게 예측할 수 있다.
실제 실행 순서는 다음과 같기 때문이다.
변수 number 선언 → 1번째 로그 → number 값(10) 할당 → 2번째 로그
console.log(number); // undefined
number = 10;
var number;
console.log(number); // 10
자바스크립트에서 var, let, const, function, class 키워드를 사용해서 선언하는 모든 식별자들은 호이스팅된다. 모든 선언문은 런타임 이전 단계에서 먼저 실행되기 때문이다.
하지만 자바스크립트를 사용하면서 아래의 코드는 참조 에러가 발생한다.
console.log(string); // ReferenceError: string is not defined
let string;
여기에서 var 키워드로 변수 선언하는 것과, let, const 키워드로 변수 선언하는 것의 차이가 있음을 알 수 있다. var 키워드로 선언한 변수는 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 ‘선언 단계’와 ‘초기화 단계’가 한번에 진행된다. 따라서 변수 선언문 이전에 변수에 접근해도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다. (undefined 반환)
var와 다르게 let 키워드로 선언한 변수는 ‘선언 단계’와 ‘초기화 단계’가 분리되어 진행된다. 따라서 let 키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계 시작 지점(변수 선언문)까지 변수를 참조할 수 없다. 스코프의 시작 지점부터 초기화 시작지점까지 변수를 참조할 수 없는 구간을 일시적 사각지(Temporal Dead Zone; TDZ)라고 부른다. let 키워드도 호이스팅이 일어난다는 것을 증명하는 예제는 다음과 같다.
let bool = true; // 전역 변수
{
console.log(bool); // Reference : Cannot access 'bool' before initialization
let bool = false; // 지역 변수
}
만약 호이스팅이 일어나지 않는다면 콘솔이 실행될 때 전역 변수 bool이 출력되어야 한다. 이는 const, class 키워드로 선언할 때도 마찬가지다.
정리하자면 let, const, class를 이용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다.
함수 호이스팅
함수 선언에서도 호이스팅이 존재하는데, 함수 표현식으로 선언하게 되면 호이스팅되지 않는다. 예제는 다음과 같다.
f1(); // f1 함수 실행
f2(); // ReferenceError: Cannot access 'f2' before initialization
// 함수 선언식
function f1() {
console.log("f1 함수 실행");
}
// 함수 표현식
const f2 = () => {
console.log("f2 함수 실행");
}
화살표 함수와 같은 함수 표현식은 호이스팅이 발생하지 않는다. (let, const의 과정과 엄밀히 다르다.)
자바스크립트가 다른 언어들에 비해 엄격하지 못한 요소들이 존재하는데, 호이스팅도 그 중 하나이다. 그래서 자바스크립트를 사용할 때 유독 이게 되네? 라고 생각되는 부분들이 많은 것 같다. 알고 있으면 문제가 없겠지만 모른 채로 잘못 알게되는 경우도 많아 이를 유의하고 정확하게 학습할 수 있도록 해야겠다.
Reference
모던 자바스크립트 Deep Dive - 저자: 이응모
'Web > JavaScript' 카테고리의 다른 글
[JS] 옵셔널 체이닝 연산자 ?.와null 병합 연산자 ?? 알아보기 (0) | 2023.05.23 |
---|---|
[React] Hook 정리 (0) | 2022.08.02 |
[JS] Truthy와 Falsy (0) | 2022.07.25 |