자바스크립트의 호이스팅
자바스크립트의 호이스팅에 대해서 오개념 유무를 점검하고 배운 내용을 정리했습니다.

호이스팅
자바스크립트의 모든 변수는 호이스팅된다. 호이스팅이란 변수, 함수, 클래스 선언을 스코프의 최상단으로 위치시키는 것을 의미한다.
변수를
var로 선언할 때는 선언함과 동시에undefined라는 값으로 초기화된다.let또는const로 선언할 때에는 초기화가 되지 않기 때문에ReferenceError에러가 발생한다.- 만약 변수가 호이스팅되지 않는다면
선언되지 않은 변수입니다.라는 식의 에러가 발생했을 것이다.
- 만약 변수가 호이스팅되지 않는다면
함수 선언문도 호이스팅된다.
함수 표현식에서는 함수의 이름만 호이스팅되고 함수 자체는 정의하기 전에는 호출할 수 없다. 옵셔널 체이닝을 사용해서 에러가 발생하는 것을 방지할 수 있다.
- 호이스팅된 함수의 이름을
typeof로 타입을 확인해보면undefined라는 값을 얻을 수 있다.
- 호이스팅된 함수의 이름을
console.log(num); // ReferenceError
let num = 100;
console.log(num); // 100
console.log(typeof introduce === "undefined");
introduce("Jane Doe"); // introduce is not a function
introduce?.("Jane Doe");
var introduce = function (name) {
const message = `Hello, I am ${name}`;
console.log(message);
return message;
};
introduce("John Doe");
예시
예전에는 호이스팅에 대해서 깊게 관심가지지 않았고 let, 또는 const 변수는 호이스팅이 되지 않는 것으로 알고 있었다. 프로젝트를 진행하면서 변수 선언 및 초기화 관련 에러를 가끔씩 마주치게 되었고 호이스팅에 대해서 다시 정리하게 되었다.
다음과 같은 상황에서도 ReferenceError가 발생한다.
let num = 10;
function increment() {
num++;
console.log(num);
let num = num + 100;
console.log(num);
}
increment();
increment 함수에서 num++은 함수 바깥 스코프에 선언된 변수의 값을 1 증가시키는 것으로 예상했었다.
함수 내부에서 num이 선언되었기 때문에 변수는 함수 최상단에 호이스팅되고, num++으로 값을 증가시키려고 하면 아직 초기화가 되지 않았기 때문에 역시 ReferenceError가 발생하는 것이다.
에러가 발생하지 않게 하려면 함수 최상단에서 변수 초기화까지 완료시키거나, 변수 선언문을 제거하여 바깥 스코프의 변수를 참조시킬 수 있다.
let _num = 10;
function increment() {
let num = _num;
num++;
console.log(num);
num = num + 100;
console.log(num);
}
increment();
let num = 10;
function increment() {
num++;
console.log(num);
num = num + 100;
console.log(num);
}
increment();
TDZ
자바스크립트의 변수가 호이스팅되기 때문에 TDZ라는 개념이 존재한다.
TDZ(Temporal Dead Zone)는 스코프의 시작 지점에서 변수가 초기화되기까지의 구간을 의미하며, 이 구간에서는 변수에 접근할 수 없다.
렉시컬 스코프가 함수가 작성된 위치에 따라 결정되는 반면, TDZ는 각 코드가 작성된 위치보다는 실행 시점에 따라 결정된다.
john변수는 함수 선언문 다음에 선언 및 초기화되도록 작성되어 있다.호이스팅에 의해 변수 선언문이 최상단에 위치하게 된다. 따라서
greeting함수 스코프에서는 선언된john변수를 참조할 수 있다.greeting함수가 호출되는 시점에는 변수가 초기화까지 되었기 때문에 에러가 발생하지 않는다.
function init() {
const greeting = () => {
const message = `Hello, I am ${john.name}`;
console.log(message);
return message;
};
const john = {
name: "John Doe",
age: 30,
region: "US",
};
greeting();
}
init();
상속되는 클래스의 경우 constructor 함수에서 super 함수가 호출되기 전까지는 this에 접근할 수 없다. super를 통해 원본 클래스에서 생성자를 호출하여 퍼블릭 속성, 메소드를 this에 바인딩하고 나서 상속 클래스 생성자에서 this에 접근 및 변경할 수 있다.
class Person {
public name: string;
public age: number;
public region: string;
constructor(name: string, age: number, region: string) {
this.name = name;
this.age = age;
this.region = region;
}
}
class Employee extends Person {
public company: string;
public department: string;
constructor(
name: string,
age: number,
region: string,
company: string,
department: string
) {
this.company = company; // ReferenceError
this.department = department; // ReferenceError
super(name, age, region);
}
}
class Employee extends Person {
public company: string;
public department: string;
constructor(
name: string,
age: number,
region: string,
company: string,
department: string
) {
super(name, age, region);
this.company = company;
this.department = department;
}
}
