의도: 호이스팅에 대해 이해하고 있고, 어떤 오류가 호이스팅 때문인가 구분할 수 있는지 확인하는 질문
나의 답안
호이스팅은 스코프 내에서 변수 선언 및 함수 선언이 코드의 실행 단계 전에 스코프의 최상단으로 끌어올려지는 동작을 의미합니다.
이는 자바스크립트의 컴파일링 과정에서 발생하며, 변수와 함수의 선언부만 끌어올려지고, 초기화나 할당은 끌어올려지지 않는다는 특징이 있습니다.
호이스팅이 발생하는 이유는 자바스크립트의 실행 과정과 연관이 있습니다.
자바스크립트는 실행 전에 코드를 두 단계로 처리합니다.
처음은 컴파일 단계로, 변수를 선언하고, 함수 선언을 스코프의 최상단으로 이동시킵니다.
그 다음은 실행 단계로, 코드를 위에서 아래로 읽으며 실행합니다.
호이스팅은 컴파일 단계에서 발생하므로, 실행 전에 선언이 스코프의 맨 위로 이동된 것처럼 보이게 됩니다.
호이스팅 동작 방식은 크게 변수 선언, 함수 선언, 클래스 선언마다 조금씩 다릅니다.
우선,var로 선언된 변수는 선언이 호이스팅되지만, 초기화는 호이스팅되지 않습니다.
따라서 선언 전에 접근하면undefined를 반환합니다.
let과const도 선언은 호이스팅되지만, 일시적 사각지대(TDZ: Temporal Dead Zone)에 의해 초기화 전에 접근할 수 없습니다.
함수 선언은 변수와 달리, 전체 함수 정의가 호이스팅됩니다.
따라서 함수 선언 전에 호출할 수 있습니다.
그러나 함수 표현식은 호이스팅되지 않으며, 변수 호이스팅 규칙을 따릅니다.
클래스 선언은 호이스팅되지만, 초기화 전에 접근하면 ReferenceError가 발생합니다.
호이스팅은 코드의 동작을 예상하기 어렵게 만들 수 있습니다.
따라서var보다는let과const를 사용하는 것이 좋고, 되도록이면 변수 선언은 코드의 최상단에서 수행하는 것이 좋습니다.
그리고 함수 선언문과 함수 표현식을 명확히 구분하여 사용하는 것이 좋습니다.
주어진 답안 (모범 답안)
호이스팅의 영어 뜻은 "끌어올리다"입니다.
그렇기에 자바스크립트의 호이스팅도 끌어올린다는 의미인데요.
바로 코드 실행 전에 변수 선언과 함수 선언을 스코프의 최상단으로 끌어올리는 것을 뜻합니다.
원래 C언어 같은 프로그래밍 언어를 사용했을 때는 변수나 함수가 무조건 상단에 선언이 되어 있어야 했습니다.
그래야 아래 줄에서 참조가 가능하기 때문입니다.
하지만 자바스크립트는 실제로 선언된 위치와 상관없이 최상단으로 선언부가 끌어올려지기에 선언 위치 앞에서도 호출이 가능해집니다.
다만 이게 함수,var,let/const의 경우에 따라 달라집니다.
함수의 경우에는 어디서든 호출이 가능하고 제대로 작동합니다.
하지만var의 경우에는 선언 전에 호출한다면undefined를 반환하게 됩니다.
그러나 이게 오히려 오류를 안 내서 불편한 나머지const,let은 선언 전에 호출하면 에러를 내보내게 되었습니다.
물론 에러는 내보내지만 호이스팅이 되지 않는 건 아니라는 점에 주의해야 합니다.
호이스팅(Hoisting)은 스코프 내에서 변수 선언 및 함수 선언이 코드의 실행 단계 전에 스코프의 최상단으로 끌어올려지는 동작을 의미한다.
이는 자바스크립트의 컴파일링 과정에서 발생하며, 변수와 함수의 선언부만 끌어올려지고, 초기화나 할당은 끌어올려지지 않는다는 특징이 있다.
자바스크립트는 실행 전에 코드를 두 단계로 처리한다.
호이스팅은 컴파일 단계에서 발생하므로, 실행 전에 선언이 스코프의 맨 위로 이동된 것처럼 보이게 된다.
호이스팅은 주로 아래와 같은 선언들에 적용된다.
varlet, const (단, 초기화 전 사용 시 에러 발생)function변수 선언 (var)
var로 선언된 변수는 선언이 호이스팅되지만, 초기화는 호이스팅되지 않는다.
따라서 선언 전에 접근하면 undefined를 반환한다.
console.log(a); // undefined
var a = 5;
console.log(a); // 5
내부 동작
var a; // 선언이 호이스팅됨
console.log(a); // undefined
a = 5; // 초기화 및 할당 (초기화는 호이스팅되지 않음)
console.log(a); // 5
let과 const
let과 const도 선언은 호이스팅되지만, 일시적 사각지대(TDZ: Temporal Dead Zone)에 의해 초기화 전에 접근할 수 없다.
TDZ는 선언된 지점부터 초기화가 이루어질 때까지의 구간이다.
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;
내부 동작: let b;는 호이스팅되지만 TDZ에 의해 초기화 전 접근 불가
함수 선언 (function)
함수 선언은 변수와 달리, 전체 함수 정의가 호이스팅된다.
따라서 함수 선언 전에 호출할 수 있다.
greet(); // "Hello, world!"
function greet() {
console.log("Hellow, world!");
}
내부 동작
function greet() {
console.log("Hello, world!");
}
greet(); // 함수 정의가 이미 호이스팅되었으므로 정상 호출 가능
함수 표현식 (var, let, const와 함께)
함수 표현식은 호이스팅되지 않으며, 변수 호이스팅 규칙을 따른다.
sayHello(); // TypeError: sayHello is not a function
var sayHello = function () {
console.log("Hi!");
};
내부 동작
var sayHello;
sayHello(); // sayHello는 undefined 상태임
sayHello = function () {
console.log("Hi!");
};
클래스 선언은 호이스팅되지만, 초기화 전에 접근하면 ReferenceError가 발생한다.
const obj = new MyClass(); // ReferenceError: Cannot access 'MyClass' before initialization
class MyClass {
constructor() {
this.name = "JavaScript";
}
}
내부 동작: class MyClass 선언은 호이스팅되지만 TDZ가 적용된다.
호이스팅은 선언된 스코프에 따라 다르게 동작한다.
window 또는 globalThis)에 바인딩된다.let, const, 블록 내에서의 함수 선언은 해당 블록 내에서만 유효하다.var 변수: 선언은 호이스팅되지만 초기화는 호이스팅되지 않음(undefined 반환)let과 const: 선언은 호이스팅되지만 초기화 전 접근 불가(TDZ 적용)console.log(x); // undefined
console.log(y); // ReferenceError
console.log(z); // ReferenceError
var x = 10;
let y = 20;
const z = 30;
function foo() {
console.log("Function foo");
}
foo(); // "Function foo"
bar(); // ReferenceError
var bar = function () {
console.log("Function bar");
};
내부 동작
var x; // 호이스팅
let y; // 호이스팅 (TDZ)
const z; // 호이스팅 (TDZ)
function foo() {
console.log("Function foo");
}
var bar; // 호이스팅
console.log(x); // undefined
console.log(y); // ReferenceError
console.log(z); // ReferenceError
x = 10;
y = 20;
z = 30;
foo(); // 정상 실행
bar(); // ReferenceError
bar = function () {
console.log("Function bar");
};
호이스팅은 코드의 동작을 예상하기 어렵게 만들 수 있으므로, 다음과 같은 권장 사항을 지키는 것이 좋다.
let과 const를 사용하여 TDZ를 활용한다.이를 통해 호이스팅으로 인한 혼란을 줄이고, 코드를 더 읽기 쉽게 작성할 수 있다.