JavaScript에서 진정한 의미의 비공개(private) 메서드를 생성하면 각 객체마다 해당 함수의 고유한 복사본이 하나씩 만들어집니다. 이 복사본들은 객체 자체가 소멸하기 전까지는 가비지 컬렉터(GC)에 의해 회수되지 않습니다.
문제의 원인
비공개 메서드는 일반적으로 생성자 함수 내부의 클로저(Closure)로 구현됩니다. 따라서 new 키워드로 새로운 인스턴스를 만들 때마다 클로저 안에 선언된 함수가 각 객체에 독립적으로 복제됩니다. 반면 프로토타입(prototype)에 정의한 메서드는 모든 인스턴스가 하나의 함수를 공유하기 때문에 메모리를 절약할 수 있습니다. 결국 객체 수가 많아질수록 메모리 사용량이 비례해서 증가하는 것이 가장 큰 단점입니다.
예제
var Student = function (name, marks) {
this.name = name || ""; // 공개 속성, 기본값은 빈 문자열
this.marks = marks || 300; // 공개 속성, 기본값은 300
// 비공개(private) 메서드
var increaseMarks = function () {
this.marks = this.marks + 10;
};
// 공개(public) 메서드 (this에 추가)
this.displayIncreasedMarks = function () {
increaseMarks();
console.log(this.marks);
};
};
// Student 객체 생성 시마다 비공개 메서드의 복사본이 함께 생성됨
var student1 = new Student("Ayush", 294);
// 마찬가지로 새로운 복사본이 생성됨
var student2 = new Student("Anak", 411);
위 예제에서 student1과 student2를 생성하면 increaseMarks라는 비공개 메서드가 각각 별도의 복사본으로 존재하게 됩니다. 객체가 두 개뿐이라면 부담이 없지만, 수백·수천 개의 인스턴스를 생성하는 애플리케이션에서는 불필요한 메모리 낭비가 상당해질 수 있습니다.
메모리 효율을 위한 대안
비공개 상태가 꼭 필요하지 않다면 메서드를 프로토타입에 정의하여 모든 인스턴스가 하나의 함수를 공유하도록 하는 것이 좋습니다. 또한 최신 JavaScript(ES2022 이상)에서는 클래스 필드의 # 문법(예: #increaseMarks())을 사용하면 진정한 비공개 메서드를 만들면서도 클래스 레벨에서 한 번만 정의할 수 있어, 프라이버시와 메모리 효율을 동시에 확보할 수 있습니다.