[나의 모닥불] 클래스에서 호이스팅이 되지 않는 이유

유소정·2025년 3월 17일
1

나의 모닥불

목록 보기
2/3
post-thumbnail

🪵 이 주제를 탐구하게 된 이유

테코톡 주제가 호이스팅이었는데, 이걸 준비하다가 생각지도 못한 충격적인 사실을 마주하게 되었다.
바로, 클래스 내부에서는 호이스팅이 일어나지 않는다는 것.

호이스팅에 대해 조원들과 이야기하던 중 누가 “클래스 내부에서는 호이스팅이 안 된다”고 했을 때,
나는 말했다.

"클래스 내부에서만 호이스팅이 안 된다고? 클래스 내부에서도 함수 표현식은 선언 전에 못 쓸 것 같은데!"

하지만 실제로 코드를 실행해보니, 클래스 내부에서 선언된 메서드는 선언 전에 잘만 실행되었다.

순간적으로 “this 때문인가?” 싶었지만,
“호이스팅은 무조건 되는 거지!”라는 고정관념이 더 컸다.

그래서 깊이 파고들었다.


🪵 결론부터 말하자면

클래스 내부에서는 호이스팅이 일어나지 않는다.

그 이유는 단순히 "클래스니까"가 아니라,
자바스크립트의 this 바인딩 방식, 스코프, 실행 시점과 밀접하게 관련되어 있다.


1️⃣ 객체 리터럴에서 this 없이 값에 접근하기

객체 리터럴 예시를 가지고 먼저 알아보자.

const obj = {
  a: 1,
  b: 2,
  sum() {
    return this.a + this.b;
  }
};

위 코드는 잘 동작한다. this가 obj를 가리키기 때문이다.

하지만 this를 빼고 아래처럼 작성하면?

const obj = {
  a: 1,
  b: 2,
  sum() {
    return a + b; // ❌ ReferenceError: a is not defined
  }
};

안된다.

x, y는 let, const, var로 선언된 스코프 변수(variable)가 아니라
단순히 obj 객체의 프로퍼티(property)이기 때문이다.

즉, x와 y는 변수처럼 참조할 수 없다.
반드시 obj.x처럼 명시적으로 접근하거나, this.x로 참조해야 한다.


✅ 객체 리터럴에 선언한 값은 스코프 변수가 아니라고?

객체 리터럴은 스코프를 가지지 않는다.

중괄호 {}를 쓰니까 얼핏 보면 스코프처럼 보이지만,
객체 리터럴은 단순한 값(expression)이기 때문에
if, for, function, class 같은 블록문과는 다르다.

{
  const x = 10;
}
console.log(x); // ❌ ReferenceError

↑ 이런 블록은 스코프를 형성한다.

const obj = {
  x: 10,
  y: 20,
  sum() {
    return x + y;  // ❌ ReferenceError: x is not defined 👈 내부에서 접근 불가능!
  }
};

console.log(x); // ❌ ReferenceError: x is not defined 👈 외부에서 접근 불가능!

↑ 객체 리터럴은 스코프를 형성하지 않는다.

따라서, 자바스크립트는 함수를 실행할 때 렉시컬 스코프를 기준으로
x, y 같은 식별자를 현재 스코프에서 찾고, 없으면 상위로 타고 올라간다.
하지만 어디에도 그런 변수가 없기 때문에 ReferenceError가 발생한다.

다시 말하자면, x, y는 obj 객체의 프로퍼티(property)로 등록된 상태라서 x, y를 this 없이 접근이 불가능하다.
만약 this 없이 접근한다면, 현재 스코프에서 찾고, 없으면 상위로 타고 올라간다.


2️⃣ 클래스는 다른가?

class Obj {
  a = 1;
  b = 2;

  sum() {
    return a + b; // ❌ ReferenceError
  }
}

마찬가지로ab스코프에 등록된 변수가 아니기 때문에 에러가 발생한다.

하지만 클래스 바디는 블록 스코프를 가진다.
그런데 중요한 점은, 클래스 필드가 그 스코프 안에 포함되지 않는다는 것이다.


✅ 클래스 필드는 왜 스코프에 등록되지 않을까?

앞서 객체 리터럴에서 설명했듯,
프로퍼티는 단순히 객체 안에 있는 키-값 쌍일 뿐이고,
스코프 체인에 등록되는 변수는 아니다.

클래스 내부에서 선언한 필드는
let, const 같은 스코프 변수로 등록되지 않고,
인스턴스를 생성할 때 this에 동적으로 추가된다.

class Person {
  name = 'Hailey';
}

이 코드는 사실상 이렇게 해석된다.

class Person {
  constructor() {
    this.name = 'Hailey';
  }
}

즉, name이라는 필드는 클래스가 정의될 때
스코프에 올라가는 게 아니라,
new 키워드로 인스턴스를 생성하는 시점에 this.name으로 할당되는 것이다.

그렇다면 클래스는 왜 스코프가 필요할까? 자바스크립트는 렉시컬 스코프 기반 언어이다. 스코프를 나누는 단위가 렉시컬(코드의 위치)에 따라 정해진다는 것이다. 때문에 블록 단위의 스코프 구분이 필수적이다. 단, 객체 리터럴은 '문'이 아니라 '값'이라서 스코프를 가지지 않는다.


3️⃣ 함수랑 비교해보면?

function outer() {
  const a = 10;
  function inner() {
    return a; // ✅ 가능! 렉시컬 스코프
  }
  return inner();
}
class MyClass {
  a = 10;
  inner() {
    return a; // ❌ ReferenceError
  }
}

→ 함수의 변수는 스코프에 등록된다.

  • 함수 안에서
    • const a = 10이라고 선언하면,
    • a는 함수 스코프에 등록된 변수가 된다.
  • 클래스 안에서
    • a = 10이라고 선언하면
    • a는 클래스 스코프에 등록되지 않는다.
    • 대신, this.a로만 접근 가능한 값으로 존재한다.

4️⃣ 클래스 내부의 요소는 종류에 따라 동작 방식이 다르다

추가적인 내용입니다!

클래스 내부에 선언한 일반 메서드는 인스턴스에 등록되지 않아서 관련 내용을 적습니다.

✅ 1. 일반 메서드

class Example {
  sayHi() {
    console.log('Hi');
  }
}
  • 정의 시점: 클래스 정의가 끝날 때
  • 등록 위치: Example.prototype.sayHi
  • 인스턴스를 생성하지 않아도 메모리에 존재

📌 일반 메서드는 prototype에 등록되기 때문에
호이스팅되지는 않지만, 클래스 정의 이후 바로 사용할 수 있다.


✅ 2. 변수, 화살표 함수

class Example {
  message = 'hello';  
  greet = () => console.log(this.message);
}
  • 정의 시점: new Example() 인스턴스 생성 시
  • 등록 위치: 생성된 인스턴스 내부 (this.message, this.greet)
  • 메모리 등록: constructor 내부에서 동작하는 것처럼 처리됨

📌 이들은 클래스 정의만으로는 메모리에 올라가지 않고,
인스턴스를 생성할 때 this에 동적으로 추가된다.


🔥 정리하자면?

클래스 내부에서는 왜 호이스팅이 안 될까?라는 단순한 의문에서 시작된 이야기였지만, 단지 “클래스니까!”라는 말로는 설명이 되지 않아 조금 길어졌습니다.

결론적으로 클래스 내부에서 선언한 필드는 let, const처럼 스코프에 등록되는 변수가 아니며, prototype에 저장되거나 인스턴스 생성 시점에 this에 동적으로 할당됩니다.

객체 리터럴은 스코프를 형성하지 않고, 클래스는 블록 스코프를 가지지만, 그 여부와 관계없이 필드는 스코프에 등록되지 않는다는 점이 핵심입니다.

그래서 객체 리터럴, 클래스 안에서는 변수처럼 단독으로 접근할 수 없고, 반드시 this를 통해 참조해야 하는 이유도 여기에 있습니다.


🍵 에필로그

이 내용을 함께 정리해준 크루들(머핀, 퐁쥬, 캉골, 해삐)에게 진심으로 감사합니다~

수성 회의실에서 무려 3시간 동안 토론하며 함께 정리했었는데,
혼자였다면 절대 이 내용을 그렇게 짧은 시간 안에 정리할 수 없었을 거예요.
'함께여서 함께 자랄 수 있었다'는 걸 정말 실감했던 시간이었습니다.

덕분에 막혔던 궁금증도 풀리고,
자바스크립트의 여러 개념들도 깊이 들여다볼 수 있었어요.

정말 감사합니다 💛

profile
기술을 위한 기술이 되지 않도록!

0개의 댓글