자바스크립트 단골 면접 질문에 도달했다.
변수 선언 방식과 스코프에 대한건 이 개념을 정리하기 위한 빌드업이었다..!
빌드업의 결과물인 호이스팅에 대해서 이번에 제대로 정리해 보자.
호이스팅이란?
[ 호이스팅 ]
인터프리터가 코드를 실행하기 전 함수, 변수, 클래스 또는 임포트의 선언문을
해당 범위의 맨 위로 이동시키는 과정을 말한다.
- MDN -
위는 MDN에서 작성한 호이스팅의 정의다.
여기서 말하는 인터프리터는 프로그래밍 언어를 번역하는 방식 중 하나인데,
대표적으로는 인터프리터와 컴파일러가 있다.
먼저 컴파일러 방식은 전체 문서를 읽고 해당 문서를 한 번에 번역하는 방식이라고 할 수 있겠고,
인터프리터 방식은 전체 문서를 한 줄씩 읽어 내려가면서 번역을 하는 방식이라 할 수 있겠다.
이 두 가지 방식 중 Javascript는 인터프리터 방식으로 문서에 대한 번역을 한다.
다시 돌아와서 호이스팅 (Hoisting)이라는 단어 자체가 끌어올리다 라는 의미를 갖고 있는데
인터프리터가 Javascript의 코드를 읽고 해석하기 전, 코드 내에 사용된 다양한 선언문을
해당 범위(스코프)의 맨 위로 끌어올리는 현상이라고 생각하면 되겠다.
console.log(test); // undefined
var test = 1;
console.log(test); // 1
console.log(check); // ReferenceError: check is not defined
let check = 1;
호이스팅에 대해서 얘기할 때, 가장 흔하게 볼 수 있는 예시다.
앞서 언급한 것처럼 자바스크립트는 인터프리터 방식으로 한 줄씩 읽어 내려가면서 코드를 해석하는데
가장 첫 줄의 console.log(test)는 어째서 undefined이라는 값을 출력한 것일까?
또 5번째 줄의 console.log(check)는 선언되지 않았다는 에러를 표시하는 것일까?
사실 인터프리터라는 방식으로 통해 이해하기로는 첫 번째 줄 역시
'test라는 변수가 선언되지 않았다'라는 에러가 발생해야 하는 게 정상인 것 같지만,
호이스팅과 var, let, const의 사이클에 대해서 이해를 하게 되면
왜 저렇게 동작을 한 것인지 알 수 있게 된다.
변수 선언과 할당의 사이클
자바스크립트에서는 변수를 선언하고 값을 할당할 때, 선언 / 초기화 / 할당 3가지 단계를 거치게 된다.
선언 단계에서는 변수를 실행 컨텍스트에 등록하고 스코프에 등록된다.
초기화 단계에서는 메모리에 변수를 할당하고, 변수에 접근할 수 있는 상태가 된다.
할당 단계에서는 변수에 실제 값을 할당하는 단계다.
선언 단계의 선언이란 코드에서 키워드를 통해 작성한 변수의 이름을 미리 등록한다는 의미다.
호이스팅이 인터프리터가 코드를 해석하기 전 선언문을 범위의 최상단으로 이동시키는 과정을 의미한다고 했는데,
물리적으로 끌어올려지는 것이 아닌 전체 코드에서 변수가 선언되는 부분을 파악해
코드를 해석하기 전 이러한 변수의 이름을 미리 등록해 놓는다는 의미가 되겠다.
아무튼 변수를 선언하는 3가지 키워드에서 동일하게 위의 3단계를 진행하게 되는데
진행되는 타이밍이 키워드 별로 조금씩 다르다.
var
console.log(test); // undefined
var test = 1;
console.log(test); // 1
var 키워드를 사용할 경우 선언과 초기화가 동시에 이루어진다.
동시에 이뤄진다는 것은 변수가 등록되고 그 값으로 초기값인 undefined가 적용된다는 것을 의미한다.
그래서 위의 예시처럼 가장 첫 줄에 console.log(test)를 했을 때, undefined가 출력되는 것이다.
let
console.log(test); // ReferenceError: test is not defined
let test = 1;
console.log(test); // 1
let 키워드를 사용할 경우 선언을 먼저 하고 그다음에 초기화가 진행되고 할당이 진행된다.
let 키워드를 사용할 경우에도 호이스팅에 의해 이름은 등록되지만
초기화가 진행이 되지 않았기 때문에 첫 줄에서 해당 변수에 접근하려고 정의되지 않았다는 에러가 나온다.
const
console.log(test); // ReferenceError: test is not defined
const test = 1;
console.log(test); // 1
const 키워드를 사용할 경우에는 선언과 동시에 초기화 및 할당이 이루어져야 한다.
var와 비교해 보면 var는 자동으로 선언과 초기화가 동시에 진행되는 거지만
const는 선언과 동시에 초기화와 할당이 이뤄져야 한다는 차이가 있다.
그래서 const 키워드를 사용해도 호이스팅에 의해 변수 이름은 등록이 되지만
초기화와 할당이 이뤄지지 않았기 때문에 정의되지 않았다는 에러가 나오게 되는 것이다.
이렇게 선언 단계를 통해 변수의 이름은 등록이 되었지만
변수 선언문을 읽는 초기화 과정까지의 시간을 TDZ라고 한다.
TDZ
TDZ ( Temporal Dead Zone ) : 일시적 사각지대
일시적 사각지대는 스코프의 시작부터 초기화 시작 지점까지의 구간을 의미하는데
이 역시 어떤 키워드로 변수를 선언하는지에 따라서 TDZ의 존재 유무가 달라지게 된다.
var의 경우 선언과 초기화가 동시에 이루어지기 때문에 TDZ는 존재하지 않는다.
그러나 let과 const의 경우에는 선언 이후 초기화 단계가 이루어지기 때문에 TDZ가 존재한다.
그래서 TDZ가 있는 시점에 변수에 접근하려는 경우 ReferenceError가 발생하게 되는 것이다.
함수 호이스팅
지금까지 변수에 대한 호이스팅을 알아봤는데, 함수에도 함수를 만드는 방법에 따라 호이스팅이 있다.
// 함수 선언식
function sum (value) {
return value + 3;
}
// 함수 표현식
const sum = (value) => {
return value + 3;
}
위의 블록을 보면 가장 위에 있는 것이 함수 선언식이고 아래 있는 것이 함수 표현식이다.
사실 메서드 동작에는 두 함수 모두 차이가 없는데, 어떤 방식으로 함수를 작성하는지에 따라
함수에 접근할 수 있는 시점이 달라지게 된다.
sum(3); // 6
function sum (value) {
console.log(value + 3);
}
함수 선언식으로 선언한 메서드는 호이스팅에 의해 함수 전체가 끌어올려지게 된다.
그래서 함수 호출하는 코드 이후에 작성한 함수라고 하더라도 동작을 하게 된다.
sum(3); // ReferenceError: sum is not defined
const sum = (value) => {
console.log(value + 3);
}
반대로 함수 표현식으로 선언한 메서드는 호이스팅에 의해 변수 이름만 등록이 된다.
구조를 보면 변수를 선언하고 그 값으로 함수를 할당한 형태기 때문에
함수를 표현식보다 먼저 호출하게 되면 해당 함수를 찾을 수 없다는 에러가 나온다.
sum(3); // TypeError: sum is not a function
var sum = (value) => {
console.log(value + 3)
}
조금 다른 점은 var의 경우는 호이스팅과 var 특징에 의해 초기화까지는 이루어졌겠지만
undefined는 함수가 아니기에 함수 호출을 만나다고 하더라도 할 수 있는 게 없다.
Summary
키워드 | 사이클 | TDZ |
var | 선언 + 초기화 / 할당 (나중에 진행 가능) | X |
let | 선언 / 초기화 / 할당 (나중에 진행 가능) | O |
const | 선언 + 초기화 + 할당 | O |
방식 | 특징 |
선언식 | 호이스팅에 의해 함수 전체가 끌어올려짐 |
표현식 | 변수 호이스팅 특징에 따름 |
함께 읽으면 좋은 글 리스트
var, let, const : 자바스크립트 변수 선언 3 대장
실행 컨텍스트 : 자 이게 너가 사용할 수 있는 친구들이야
포스팅 작성에 참고한 감사한 글들
'Stack > JS' 카테고리의 다른 글
This : 이거라며.. 왜 다르냐고 (1) | 2024.11.15 |
---|---|
클로저 (Closure) : 자바스크립트의 네크로멘서 (3) | 2024.11.11 |
실행 컨텍스트 : 자 이게 너가 사용할 수 있는 친구들이야 (6) | 2024.11.08 |
Scope : 변수, 너에게 닿을 수 있는 그 범위 (1) | 2024.11.02 |
var, let, const : 자바스크립트 변수 선언 3대장 (0) | 2024.10.31 |