How to implement hidden methods in JavaScript classes

I’m trying to figure out how to create methods that can only be accessed from within a JavaScript class. Let me show you what I mean.

Right now I have a basic class setup like this:

function Library() {}

Library.prototype.borrow_book = function(){
   // code goes here
}

Library.prototype.return_item = function(){
   // code goes here
}

Users can create instances and call these methods:

var library = new Library();
library.borrow_book();
library.return_item();

What I need is a way to create internal methods that my public methods can use, but external code cannot access directly. For example, I want to be able to do this inside my class:

Library.prototype.borrow_book = function() {
   this.internal_validation();
}

But I don’t want external code to be able to call it:

var lib = new Library();
lib.internal_validation(); // this should not work

Is there a way to define internal_validation so it stays hidden from outside access but can still be used by my public methods?

Hit this same issue building internal APIs for data validation. The approaches people mentioned work, but maintaining them across multiple classes is a nightmare.

I automate the whole private method generation process now. Why hand-code closures or IIFEs for every class when you can set up workflows that generate proper encapsulation patterns automatically?

For your Library example, create templates that output the module pattern structure, handle private function scoping, and generate docs marking which methods are internal only.

The real payoff comes with 20+ classes needing similar private method patterns. Manual coding means constant refactoring and inconsistent implementations everywhere.

I use automation to generate clean JavaScript with proper encapsulation, test the private method isolation, and deploy everything consistently. Kills the tedious work of implementing these patterns over and over.

Bonus: version control your templates and update privacy implementations across your entire project at once.

Latenode handles this code generation workflow perfectly. Way cleaner than maintaining dozens of hand-coded closure patterns.

The Problem:

You want to create methods within a JavaScript class that are accessible only from inside the class, not externally. You’re currently using prototype-based inheritance and want to restrict access to certain methods.

:thinking: Understanding the “Why” (The Root Cause):

In JavaScript, true private methods are not directly supported by the language when using prototype-based inheritance as you are. Methods defined on the prototype are, by design, accessible to any instance of the class. While techniques exist to simulate private methods, they rely on conventions or mechanisms that don’t provide absolute, language-enforced privacy.

:gear: Step-by-Step Guide:

  1. Using Private Class Fields (Modern JavaScript): The cleanest approach for modern JavaScript uses private class fields (introduced in ES2022). This offers the best balance of readability, maintainability and true privacy. If you can refactor your code to use ES6 classes, this is the preferred solution:
class Library {
  #internalValidation() {
    // Truly private method implementation
    console.log('Validating...');
  }

  borrowBook() {
    this.#internalValidation();
    // Public method implementation
  }

  returnItem() {
    this.#internalValidation();
    // Public method implementation
  }
}

const library = new Library();
library.borrowBook(); // Works
library.returnItem();// Works
library.#internalValidation(); // This will throw an error!
  1. Using the Underscore Convention (Prototype-Based): If you cannot switch to ES6 classes, you can adopt the common JavaScript convention of prefixing private methods with an underscore (_). This is not truly private, but it strongly signals to other developers that the method should not be accessed directly:
function Library() {}

Library.prototype._internalValidation = function() {
  // Treat as private
  console.log('Validating...');
};

Library.prototype.borrow_book = function() {
  this._internalValidation();
};

Library.prototype.return_item = function() {
  this._internalValidation();
};


const library = new Library();
library.borrow_book(); // Works
library._internalValidation(); // Works, but strongly discouraged!

:mag: Common Pitfalls & What to Check Next:

  • Underscore Convention is a convention, not enforcement: While the underscore convention is widely understood, it doesn’t prevent direct access to the method. Any developer could still call library._internalValidation().
  • Modern JavaScript is Better: If you’re starting a new project or have the option to refactor, migrating to ES6 classes with private class fields is the superior approach.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

There are several ways to handle this, but here’s what works best in production.

Cleanest approach is closures with a factory function:

function createLibrary() {
  function internalValidation() {
    // hidden logic here
  }
  
  function Library() {}
  
  Library.prototype.borrowBook = function() {
    internalValidation();
    // public logic here
  };
  
  return Library;
}

const Library = createLibrary();
const lib = new Library();
lib.borrowBook(); // works
lib.internalValidation(); // undefined

You can also use WeakMap for truly private methods:

const privateMethod = new WeakMap();

function Library() {
  privateMethod.set(this, {
    validate: function() {
      // private logic
    }
  });
}

Library.prototype.borrowBook = function() {
  privateMethod.get(this).validate();
};

But complex class structures with reliable encapsulation across different environments? Manual coding gets messy fast.

I’ve automated this whole pattern using Latenode. It generates clean factory functions with proper closure scoping and handles the boilerplate. Plus it integrates with your build process so you don’t manually maintain these patterns across dozens of classes.

Saved me tons of time on our last project with similar encapsulation requirements.

iife is def the way to go, but if you gotta stick to prototypes, try namespacing your private methods differently. I usually use Library.prototype.__internal_validation with double underscores - not 100% foolproof, but it keeps things organized and most devs won’t mess with it by accident.

Had this exact problem building a payment processing module last year. Module pattern with an IIFE worked best:

var Library = (function() {
  function internal_validation() {
    // private implementation
    console.log('validating...');
  }
  
  function Library() {
    // constructor code
  }
  
  Library.prototype.borrow_book = function() {
    internal_validation(); // accessible here
    // rest of public method
  };
  
  Library.prototype.return_item = function() {
    internal_validation(); // accessible here too
  }; 
  
  return Library;
})();

You get true privacy without the memory overhead of closures per instance. Private functions exist once in module scope - all instances share them. External code can’t touch internal_validation since it’s trapped in the IIFE. Used this for years, works perfectly across all browsers.

You could use symbols for semi-private methods too. they’re not completely hidden, but users won’t hit them by accident:

const _validate = Symbol('validate');

function Library() {}

Library.prototype[_validate] = function() {
  // internal stuff
};

Library.prototype.borrow_book = function() {
  this[_validate]();
};

Works great unless someone’s really digging around in your object.

This topic was automatically closed 6 hours after the last reply. New replies are no longer allowed.