Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A private method in JavaScript is a class-level function strictly encapsulated within the lexical scope of its defining class. Denoted by a hash (#) prefix, these methods are inaccessible from outside the class body, including from instances of the class or its subclasses. Introduced in ECMAScript 2022, they provide language-level enforcement of encapsulation, evaluated at parse time, rather than relying on developer conventions.

Syntax and Declaration

The # symbol is an inherent part of the method’s identifier, not an access modifier keyword. Private methods can be declared as instance methods, static methods, or accessor properties (getters and setters).
class Processor {
  // Private instance method
  #executeTask() {
    return 'Task complete';
  }

  // Private static method
  static #initializeEngine() {
    return 'Engine ready';
  }

  // Private getter
  get #internalState() {
    return true;
  }

  // Public method accessing private members
  run() {
    Processor.#initializeEngine();
    return this.#executeTask();
  }
}

Technical Mechanics and Behavior

Lexical Scoping and Hard Privacy Private methods are evaluated relative to the class environment in which they are defined. Attempting to reference a private method from outside this lexical scope results in an immediate SyntaxError during the parsing phase, preventing the code from executing entirely. Dynamic Access Restriction Unlike public methods, private methods cannot be accessed dynamically using bracket notation. The # identifier is resolved lexically. Attempting to use bracket notation looks for a public property whose string key literally includes the hash character, which evaluates to undefined and throws a standard runtime error when invoked.
class Container {
  #formatData() {
    return 'Formatted';
  }

  testAccess() {
    // Valid: Lexical access
    this.#formatData(); 
    
    // Invalid: Looks for a public property named "#formatData", evaluates to undefined
    // this['#formatData'](); // TypeError: this["#formatData"] is not a function
  }
}

const instance = new Container();

// Invalid: Lexical scope violation (Parse-time error)
// instance.#formatData(); // SyntaxError: Private field '#formatData' must be declared in an enclosing class
Receiver Validation (Brand Checking) While lexical scoping prevents out-of-bounds access at parse time, JavaScript also enforces receiver validation at runtime. If a private method is accessed inside its valid lexical scope, but the receiver (the object the method is called on) was not instantiated by the class that declares the private method, the engine throws a TypeError. This ensures the object possesses the internal “brand” of the class.
class Emitter {
  #emit() {
    return 'Emitting data';
  }

  static trigger(obj) {
    // Valid lexically, but runtime validation depends on 'obj'
    return obj.#emit(); 
  }
}

const validInstance = new Emitter();
Emitter.trigger(validInstance); // 'Emitting data'

const invalidInstance = {};
// Emitter.trigger(invalidInstance); // TypeError: Cannot read private member #emit from an object whose class did not declare it
Ergonomic Brand Checks (in Operator) To safely verify if an object possesses a specific private method without triggering a runtime TypeError, ES2022 introduced the ability to use the in operator with private identifiers. This performs an ergonomic brand check, returning a boolean indicating whether the private method exists on the receiver.
class Emitter {
  #emit() {
    return 'Emitting data';
  }

  static isSafeToTrigger(obj) {
    // Safely checks for the private method's presence
    if (#emit in obj) {
      return obj.#emit();
    }
    return 'Invalid object';
  }
}

Emitter.isSafeToTrigger(new Emitter()); // 'Emitting data'
Emitter.isSafeToTrigger({});            // 'Invalid object'
Inheritance and Subclassing Private methods are not inherited by subclasses. A subclass cannot invoke a parent class’s private method, nor can it override it. If a subclass declares a private method with the exact same # identifier as the parent, it creates a completely separate, shadowed method bound exclusively to the subclass’s lexical scope.
class Parent {
  #compute() {
    return 'Parent computation';
  }
}

class Child extends Parent {
  execute() {
    // Invalid: Lexical scope violation (Parse-time error)
    // return this.#compute(); // SyntaxError: Private field '#compute' must be declared in an enclosing class
  }
}
Memory Allocation Unlike public methods, which are typically attached to the class prototype, private instance methods are installed directly on the instance itself during object construction (conceptually similar to properties defined in the constructor). However, JavaScript engines highly optimize this process to share the underlying function reference across instances, avoiding the memory overhead of recreating the function per instance. Private static methods are attached directly to the class constructor object.
Master JavaScript with Deep Grasping Methodology!Learn More