자바스크립트 호이스팅

Jemin·2023년 5월 27일
0

프론트엔드

목록 보기
11/51
post-thumbnail

호이스팅이란

호이스팅(hoisting)은 자바스크립트 엔진이 코드를 해석하는 과정에서 변수 및 함수 선언을 스코프의 상단으로 끌어올리는 동작이다. 이는 변수와 함수가 실제 선언된 위치와는 상관없이 해당 스코프의 맨 위로 이동하여 처리된다.

따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있다. 다만, 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 된다.

console.log(value); // undefiend

var value = "hello";

console.log(value); // hello

ReferenceError는 발생하지 않으나 자바스크립트는 호이스팅 된 var 변수를 undefined로 초기화한다.

위 소스 코드는 인터프리터가 다음과 같이 해석한다.

var value; // undefined로 초기화

console.log(value); // undefined

value = "hello";

console.log(value); // hello

변수 호이스팅

변수 호이스팅은 변수 선언문이 해당 스코프의 상단으로 끌어올려지는 것을 의미한다. 이로 인해 변수 선언 전에 변수를 참조할 수 있다. 하지만 호이스팅은 변수의 할당 과정을 끌어올리지 않으므로 변수를 선언하기 전에 해당 변수에 접근하면 undefined값을 갖게 된다. 이후 변수의 할당은 실제 선언문이 위치한 곳에서 이루어진다.

제발 var 변수를 사용하지 마세요

웹 퍼블리셔 시절부터 공부하면서 여러번 봤던 문구다.
var 변수때문에 리펙토링하다가 멘탈이 나가신 개발자분의 글이었던 것 같다.🤔

자바스크립트 개발에서 var 변수를 사용하는 것을 권장하지 않는 이유는 다음과 같다.

  1. 함수 스코프: var 변수는 함수 스코프를 가진다. 즉, 변수가 선언된 함수 내에서만 유효하며, 블록 스코프를 가지지 않는다. 이로 인해 변수의 범위가 예상치 못하게 확장되거나 충돌이 발생할 수 있다.

  2. 호이스팅 문제: var 변수는 호이스팅되어 선언이 해당 스코프의 상단으로 이동과 동시에 undefiend로 초기화된다. 이로 인해 변수가 선언되기 전에도 참조할 수 있게 되며, 이는 예기치 않은 동작을 유발할 수 있다.

  3. 중복 선언 허용: var 변수는 동일한 이름으로 중복 선언할 수 있다. 이로 인해 의도치 않은 변수의 값을 덮어쓸 수 있으며, 버그를 발생시키기 쉽다.

  4. 블록 스코프 미지원: var 변수는 블록 스코프를 지원하지 않는다. 따라서 if, for, while 등의 블록 내에서 선언된 변수도 함수 스코프를 가지게 된다. 이는 예기치 않은 변수 유효 범위를 생성하고, 코드의 가독성과 유지보수성을 저하시킬 수 있다.

이러한 이유로 var 변수보다는 let 또는 const를 사용하는 것이 권장된다. letconst는 블록스코프를 가지며, 중복 선언이 허용되지 않고 호이스팅 문제도 해결된다. 또한 const는 재할당이 불가능한 상수를 선언하는 데 사용되어 변수 값의 변화를 방지할 수 있다.

따라서 최신 자바스크립트에서는 var 보다는 letconst를 사용하여 변수를 선언하는 것이 좋다.


예시를 보자.

let foo = 1;
{
  console.log(foo);
  let foo = 2;
}

위 코드의 결과는 무엇일까? 본인은 처음에 1이라고 생각했는데 ReferenceError가 발생했다.

왜 에러가 발생하냐면 var는 키워드 선언과 함께 undefined로 초기화되어 메모리에 저장되는 데 letconst는 초기화되지 않는 상태로 선언한 메모리에 저장되기 때문이다. 초기화 되지 않으면 변수를 참조할 수 없다. 그래서 참조 에러를 일으키는 것이다.

호이스팅이 일어나지 않는다면 아래 코드에서 에러가 발생하지 않을 것이다. 선언이 호이스팅되었기 때문에 블록 스코프에서 foo를 찾을 수 없는 것이다.

TDZ(Temporal Dead Zone)

TDZ(Temporal Dead Zone, 일시적 사각지대)는 letconst 변수가 선언되기 전에 참조할 때 발생하는 현상을 말한다. TDZ는 변수가 선언된 위치에서부터 초기화되기 전까지의 범위를 나타낸다.

TDZ는 다음과 같은 특징을 가진다.

  1. 참조 에러: TDZ에서 변수를 참조하면 "ReferenceError: 변수명 is not defined"와 같은 에러가 발생한다. 이는 변수가 선언되기 전에 엑세스하려고 하면 에러가 발생한다는 의미다.

  2. 스코프 범위: TDZ는 변수가 선언된 블록 스코프 내에서만 적용된다. 따라서 변수가 선언된 블록 스코프 외부에서는 해당 변수에 대한 TDZ가 적용되지 않는다.

  3. 호이스팅: letconst 변수도 호이스팅이 발생하지만, TDZ때문에 변수를 선언하기 전에 참조하면 에러가 발생한다. 즉, 변수가 호이스팅되어 스코프 상단으로 이동하지만 TDZ내에서는 참조할 수 없다.

TDZ는 변수 선언의 위치에 의미를 부여하고, 변수를 사용하기 전에 선언하는 것을 권장한다. 이를 통해 코드의 가독성을 높이고, 예기치 않은 동작과 버그를 방지할 수 있다. 따라서 letconst 변수를 사용할 때 TDZ에 주의해야 한다.

변수 생성 과정

자바스크립트에서 변수 생성은 다음과 같은 과정을 거친다.

  1. 변수 선언: 변수를 선언할 때 사용되는 키워드는 var, let, const 다. var 는 예전에 사용되던 변수 선언 방식(함수 스코프)이며, letconst는 ES6에서 도입된 블록 스코프 변수다.

  2. 변수 호이스팅: 자바스크립트에서 변수 선언은 해당 스코프의 맨 위로 호이스팅된다. 이것은 변수 선언이 실제 코드의 상단으로 이동되는 것을 의미한다. 변수 호이스팅은 var 변수에만 적용된다. letconst 변수는 호이스팅되지만, 초기화되기 전까지는 참조할 수 없다.

  3. 변수 초기화: 변수 선인 시 값의 할당이 함께 이루어지면 변수는 초기화된다. 초기화는 선언된 변수에 값을 할당하는 과정을 말한다. var 변수는 선언과 동시에 undefiend로 초기화 된다. letconst 변수는 선언 후 초기화되기전까지 사용할 수 없으며, 초기화되기 전에 참조하면 ReferenceError가 발생한다.

  4. 변수 할당: 변수에 값을 할당하는 과정이다. 할당은 변수에 저장할 값을 지정하는 것을 의미한다. 할당은 변수가 이미 선언되고 초기화된 후에 수행된다.

  5. 변수 사용: 변수를 참조하거나 수정하여 프로그램의 다른 부분에서 사용할 수 있다. 변수를 사용하여 값을 읽거나 변경할 수 있다.

그렇다면 코드 실행 전에 선언된 변수를 메모리에 먼저 할당하는 것인가?🤔
=> 아니다. 호이스팅은 변수와 함수 선언을 스코프의 상단으로 끌어올리는 것이지만, 실제로 메모리에 할당하는 것은 아니다. 실제 메모리 할당은 변수가 선언될 때 이루어진다.

함수 호이스팅

함수 호이스팅은 함수 선언문이 스코프의 상단으로 끌어올려지는 것을 의미한다. 따라서 함수 선언문은 선언 이전에도 호출할 수 있다. 함수 호이스팅은 함수 선언문 전체를 끌어올리기 때문에 함수 내부의 코드도 함께 끌어올려진다. 이는 함수 선언문이 어디서든지 호출될 수 있다는 특징을 갖는다. 그러나 함수 표현식(변수에 함수를 할당하는 형태)는 호이스팅되지 않으며, 변수 선언부만 호이스팅된다.

마무리

호이스팅은 자바스크립트 엔진이 코드를 해석하는 과정에서 발생하며, 개발자의 코드 작성 방식에 영향을 줄 수 있다. 호이스팅은 가독성과 코드 이해를 어렵게 만들 수 있으므로 변수와 함수 선언을 스코프 상단에 명시적으로 위치시키는 것이 권장된다. 이를 통해 코드의 의도를 명확히 전달하고 예상치 못한 동작을 방지할 수 있다.

참고
[JavaScript] 호이스팅(Hoisting)이란
[JavaScript] 변수와 함수 호이스팅(Hoisting)에 대해 알아보자

profile
꾸준하게

0개의 댓글