Emulating Private Methods in JavaScript

Mastering Encapsulation: Techniques to Emulate Private Methods in JavaScript

Patrick Karsh
3 min readOct 7, 2023

In many object-oriented programming languages, “private” methods are employed to hide internal details of a class, allowing only publicly exposed methods and properties to be accessed from the outside. However, JavaScript, being a dynamic and unique language, lacks native private methods in the traditional sense. But, worry not! Several techniques can emulate private methods in JavaScript, ensuring that class internals are not easily accessible.

The Power of Closures

The concept of closures in JavaScript allows functions and variables to be “encapsulated” or “hidden” within an outer function, making them inaccessible from the outer scope. This foundational concept can be used to emulate private methods:

function MyClass() {
let privateMethod = function() {
console.log('I am private');
};

this.publicMethod = function() {
privateMethod();
};
}

let obj = new MyClass();
obj.publicMethod(); // Outputs: "I am private"

Here, privateMethod is only accessible within the scope of MyClass. Calling obj.privateMethod() directly will result in an error.

Symbols: Unique and Hidden

Symbols, introduced in ECMAScript 2015 (ES6), provide a way to create unique, non-string object keys. This uniqueness can be harnessed to create properties and methods that are hard to access accidentally:

const _privateMethod = Symbol('privateMethod');

class MyClass {
constructor() {
this[_privateMethod] = function() {
console.log('I am private');
};
}

publicMethod() {
this[_privateMethod]();
}
}

let obj = new MyClass();
obj.publicMethod(); // Outputs: "I am private"

Although not strictly private, this[_privateMethod] is not easily accessible due to the unique symbol key.

WeakMap: Holding Private State

WeakMap is another ES6 addition that can help with private data. It allows keys to be garbage-collected if there are no references to them, ensuring that the private state doesn't prevent garbage collection. This mechanism can store private methods and data:

const privateData = new WeakMap();

class MyClass {
constructor() {
privateData.set(this, {
privateMethod: () => {
console.log('I am private');
}
});
}

publicMethod() {
privateData.get(this).privateMethod();
}
}

let obj = new MyClass();
obj.publicMethod(); // Outputs: "I am private"

The method stored in the WeakMap is only accessible using the instance as the key, making it a viable method for emulating private behavior.

Native Private with # in ES2020

The ECMAScript 2020 specification brought one of the most anticipated features: private fields and methods for classes. By prefixing a method or property with the # character, it is made private, meaning it cannot be accessed from outside the class:

class MyClass {
#privateMethod() {
console.log('I am private');
}

publicMethod() {
this.#privateMethod();
}
}

let obj = new MyClass();
obj.publicMethod(); // Outputs: "I am private"

Attempting to access obj.#privateMethod() directly will result in a syntax error. This feature represents the most straightforward way to have private behavior in modern JavaScript.

Conclusion

While JavaScript’s dynamic nature might seem like a deterrent for those seeking traditional OOP features, its flexibility offers multiple paths to emulate private methods. From using the power of closures to leveraging ES6’s symbols and WeakMap, developers have a variety of tools at their disposal. However, for those who desire true private methods in classes, ES2020's private fields and methods come to the rescue.

Regardless of the chosen approach, it’s essential to understand the underlying mechanisms, ensuring that the developer uses these tools effectively and for the right reasons. As JavaScript continues to evolve, it strikes a balance between its dynamic nature and the rigidity required for large-scale applications. Whether through emulation or native support, private methods are now a part of the JavaScript toolkit.

--

--

Patrick Karsh

NYC-based Ruby on Rails and Javascript Engineer leveraging AI to explore Engineering. https://linktr.ee/patrickkarsh