Menu

자바스크립트 private 필드: # 문법으로 클래스 캡슐화하기

# 접두사로 클래스 필드와 메서드를 진짜 private하게 만드는 방법. 문법, 규칙, 그리고 밑줄(_) 컨벤션만으로는 왜 부족한지 정리합니다.

언더스코어(_) 방식의 한계

오랜 기간 동안 자바스크립트에는 private 필드라는 개념 자체가 없었습니다. 그래서 관례적으로 프로퍼티 이름 앞에 언더스코어(_)를 붙여두고 "이건 건드리지 마세요"라고 암묵적으로 약속하는 수밖에 없었죠:

index.js
Output
Click Run to see the output here.

_count는 얼핏 private처럼 보이지만 실제로는 그렇지 않습니다. 외부에서 누구든 읽고, 쓰고, 심지어 삭제까지 할 수 있죠. 밑줄(_)은 "건드리지 마세요"라고 붙여둔 안내문일 뿐, 문 자체는 활짝 열려 있는 셈입니다.

최신 자바스크립트에서는 이 문제를 해결하기 위해 #로 표시하는 진짜 private 필드를 도입했습니다.

#를 붙이면 진짜 private이 됩니다

자바스크립트 private 필드를 만들려면 선언부와 사용하는 모든 곳에서 필드 이름 앞에 #를 붙여주면 됩니다:

index.js
Output
Click Run to see the output here.

클래스 내부에서는 this.#count를 평소처럼 쓸 수 있지만, 외부에서는 아예 존재하지 않는 것처럼 동작합니다:

index.js
Output
Click Run to see the output here.

#은 말 그대로 필드 이름의 일부입니다. 다른 언어의 private 같은 수식어(modifier) 키워드가 아니라, 파서가 객체의 별도 보호된 슬롯을 찾을 때 사용하는 기호(sigil)죠. 그래서 코드가 실행되기도 전, 파싱 단계에서 에러가 나는 겁니다.

private 메서드와 getter

private으로 지정할 수 있는 건 필드만이 아닙니다. 메서드, getter, setter 모두 # 접두사를 붙일 수 있습니다:

index.js
Output
Click Run to see the output here.

#assertPositive는 내부에서만 쓰는 헬퍼입니다. 공개 API가 아니기 때문에 완전한 private으로 만들어두면 외부에서 실수로 호출할 일도 없고, 누군가 이 메서드에 의존할 수도 없습니다. 덕분에 나중에 이름을 바꾸거나 아예 삭제해도 부담이 없죠.

private static 멤버

static 멤버도 private으로 만들 수 있습니다. 방식은 똑같이 앞에 #를 붙이면 됩니다:

index.js
Output
Click Run to see the output here.

Private static 필드는 인스턴스가 아니라 클래스 자체에 붙습니다. 카운터나 캐시, 또는 클래스 밖으로 새어 나가면 안 되는 설정값 같은 걸 담아둘 때 유용하죠.

서브클래스에서는 접근 불가

Java나 C#을 쓰다 넘어온 분들이 여기서 자주 헷갈립니다. 자바스크립트의 private 필드는 _인스턴스 단위_가 아니라 _클래스 단위_로 private입니다. 그래서 서브클래스라 하더라도 부모 클래스의 private 필드에는 손을 댈 수 없어요:

index.js
Output
Click Run to see the output here.

자바스크립트에는 protected가 없습니다. 서브클래스가 부모의 데이터에 접근해야 한다면, 부모 쪽에서 메서드나 getter를 노출하거나(드물게는) private이 아닌 필드로 열어줘야 합니다. 이건 의도된 설계입니다. private은 말 그대로 private이고, 상속이라고 해서 이 벽에 구멍을 뚫을 수는 없습니다.

in 연산자로 private 필드 확인하기

어떤 객체가 내 클래스의 인스턴스가 맞는지 확인하고 싶을 때가 있습니다. 이른바 브랜드 체크(brand check) 죠. 클래스 내부에서는 in 연산자를 private 필드 이름과 함께 쓸 수 있습니다:

index.js
Output
Click Run to see the output here.

#balance 필드를 만들 수 있는 건 오직 Wallet 클래스뿐이므로, #balance in objobj가 진짜 Wallet 인스턴스인지 확인하는 확실한 방법입니다. private 필드는 외부에서 위조할 수 없기 때문에 어떤 경우에는 instanceof보다 더 빠르고 안전한 판별법이 되죠.

주의할 점: 일반 객체에는 private 필드가 없습니다

private 필드는 클래스 생성자가 만든 인스턴스에만 존재합니다. new로 생성하지 않은 객체에 접근하려 하면 에러가 납니다.

index.js
Output
Click Run to see the output here.

thisPoint 인스턴스가 아닌 상태로 메서드를 호출하면 런타임 에러가 납니다. 앞서 본 brand check가 이런 방식으로 동작하죠. 즉, private 필드는 "그럴듯하게 생긴 객체"가 아니라 해당 필드를 선언한 클래스 자체에 묶여 있다는 뜻입니다.

언제 # private 필드를 써야 할까

클래스의 공개 API가 아닌 상태나 헬퍼라면, 기본값으로 자바스크립트 private 필드를 쓰세요. 이유는 이렇습니다.

  • 리팩터링이 자유롭다. 바깥에서 아예 볼 수 없는 내부 구현에는 의존할 수가 없습니다.
  • 진짜 캡슐화가 된다. 외부 코드가 실수로 읽거나, 쓰거나, 지울 일이 없습니다.
  • 자동완성이 깔끔해진다. 에디터가 외부 호출자에게 private 멤버를 추천하지 않습니다.

진짜로 인터페이스의 일부인 값은 public 프로퍼티로 두세요. private 필드를 읽기 전용으로 노출하고 싶다면 getter(get name())를 쓰면 됩니다. 언더스코어(_) 컨벤션은 이제 잊어도 됩니다. 언어 차원에서 채워진 빈자리를 임시로 메우던 관습일 뿐이니까요.

index.js
Output
Click Run to see the output here.

#celsius는 외부에 노출되지 않는 저장 공간이고, celsiusfahrenheit는 읽기 전용 뷰 역할을 합니다. 호출하는 쪽에서 내부 상태를 망가뜨릴 수 없고, 클래스는 나중에 값을 저장하는 방식을 얼마든지 바꿔도 괜찮습니다.

다음은 프로토타입

사실 클래스는 자바스크립트의 프로토타입 시스템 위에 얹힌 문법적 설탕(syntactic sugar)에 가깝습니다. 프로토타입이야말로 이 언어가 실제로 기반을 두고 있는, 더 오래되고 근본적인 모델이죠. 프로토타입을 이해하면 this가 왜 그런 식으로 동작하는지, 상속이 실제로 어떻게 이뤄지는지, 그리고 클래스의 extends가 내부적으로 무엇을 하는지 자연스럽게 풀립니다. 바로 다음 페이지에서 다뤄 보겠습니다.

자주 묻는 질문

자바스크립트에서 private 필드는 어떻게 선언하나요?

필드 이름 앞에 #을 붙이면 됩니다. 선언할 때도, 접근할 때도 항상 #을 함께 써야 해요. 예를 들어 class Counter { #count = 0; increment() { this.#count++; } }처럼 쓰면 진짜 private 필드가 됩니다. 여기서 #은 연산자가 아니라 이름의 일부라는 점을 기억하세요.

#field_field는 어떻게 다른가요?

_field는 "건드리지 말아주세요"라는 관례일 뿐입니다. 실제로는 완전히 public이라 누구나 읽고 쓸 수 있어요. 반면 #field는 언어 차원에서 강제됩니다. 클래스 바깥에서는 접근 자체가 불가능하고, 시도하면 파싱 단계에서 SyntaxError가 발생하죠. 진짜 비공개가 필요하면 #을 쓰세요.

서브클래스에서 부모 클래스의 private 필드에 접근할 수 있나요?

접근할 수 없습니다. private 필드는 선언한 클래스 안에서만 유효하기 때문에 자식 클래스도 손댈 수 없어요. 자식 쪽에서 접근이 필요하다면 부모 클래스가 메서드나 getter로 열어줘야 합니다. 다른 언어의 protected보다 더 엄격한 규칙인데, 의도된 설계입니다.

객체에 특정 private 필드가 있는지 확인할 수 있나요?

네, 클래스 내부에서 in 연산자를 쓰면 됩니다. #field in objtrue를 반환하면 해당 private 필드를 가진 객체라는 뜻이에요. 메서드를 호출하기 전에 "이 객체가 정말 우리 클래스의 인스턴스인가?"를 검증하는 브랜드 체크(brand check) 용도로 유용합니다.

Coddy로 코딩 배우기

시작하기