Search code examples
javascriptsingletonclone

How to prevent a Singleton object from being cloned?


I have implemented the Singleton pattern in the following way:

class Singleton {
  static #instance_holder = [];
  constructor() {
    if (0 !== Singleton.#instance_holder.length) return Singleton.#instance_holder[0];
    Singleton.#instance_holder.push(this);
    Object.preventExtensions(this);
    console.log("You'll see me only once, when the object is first instantiated.");
  }
}

This seems to work fine as far as regular declaration/assignment is concerned:

const s1 = new Singleton();
//OUTPUT: You'll see me only once, when the object is first instantiated.

const s2 = new Singleton(); //no additional instantiation, the existing one is assigned to s2

s1 instanceof Singleton //true
s2 instanceof Singleton //true
s1 === s2 //true

However, it is still possible to clone the instance (s1) using Object.create or Object.assign or JSON.parse(JSON.stringify(s1)).

const clone = Object.create(s1);

clone instanceof Singleton //true
clone === s1 //false

How can I prevent the object from being cloned in these ways?


Solution

  • Basically, you can't. There isn't a JS mechanism that would prevent cloning.

    If it is super important that something be a singleton, it is probably something in that class that you really care about. In that case, it'd be best if you put that something in the global scope and have your class reference it.

    const data = {};
    
    class Singleton {
      // singleton setup
    
      doSomething() {
        return data.something();
      }
    }
    

    This would ensure that even if the singleton was cloned, as long as it is using the same data source, it still acts like a singleton.

    That said... I really don't recommend doing this. I can't really think of a circumstance where you'd actually need to enforce a true singleton. If someone does something goofy with their code, that's their problem.