3

I have to evaluate if an instance of a class came from a Singleton or no?

I know that in JavaScript to create a Singleton I need to save in the constructor a variable instance (the name could be whatever) that save this.

class Singleton {
  constructor() {
    const instance = this.constructor.instance;
    if (instance) return instance;
    this.constructor.instance = this;
  }
}

But if I don't have that code and I just get back the instance of the class, for example:

let singletonOrMaybeNo = new Singleton()

And I just have singletonOrMaybeNo;

How can I know if that instance is a Singleton or No?

Thanks!!

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
Ruben Saucedo
  • 239
  • 1
  • 13
  • 5
    But ... why? ... – Jonas Wilms Jul 11 '19 at 12:46
  • Why would you use a constructor for a singleton, and why do you care if an object is a singleton or not? – RobG Jul 11 '19 at 13:01
  • @bionicCode who defines what a "true Singleton" is? You seem to be mixing up Java and JS, which are entirely different worlds ... Honestly, "singleton classes" are really unneccessary constructs in JS, thats what objects are for. – Jonas Wilms Jul 11 '19 at 13:12
  • @bionicCode the OPs code fullfills that premise. There can only be one instance of `Singleton` (if we ignore the short-lived instance constructed on the constructor call, that gets thrown away afterwards). Your definition of a singleton class comes from a different baclground (C# ?) and thus can't be applied to a JavaScript question. That you prefer another language over JS is your personal opinion, and I don't know why it's relevant to share that. – Jonas Wilms Jul 11 '19 at 13:40

3 Answers3

3

You could check for same identity, of the instance with the same constructor.

class Singleton {
  constructor() {
    const instance = this.constructor.instance;
    if (instance) return instance;
    this.constructor.instance = this;
  }
}

class NoSingleton {
  constructor() {
  }
}


let singletonOrMaybeNo = new Singleton,
    other = new NoSingleton;

// works only with known constructor
console.log(singletonOrMaybeNo === new Singleton);

// takes the constructor from the instance (kudos to Jonas Wilms)
console.log(singletonOrMaybeNo === new singletonOrMaybeNo.constructor);

console.log(other === new other.constructor);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Why is using identity different to `instanceof`? I haven't seen this approach before (but I like it :)) – Jack Bashford Jul 11 '19 at 12:49
  • 1
    @JackBashford this checks to see if repeated calls to some arbitrary constructor return the exact same object. It's a good idea, though it's not 100% certain that all calls to the constructor will return the same object *forever*. – Pointy Jul 11 '19 at 12:50
  • 2
    `new singletonOrMaybeNo.constructor` would be the general case. – Jonas Wilms Jul 11 '19 at 12:50
  • This does not answer the question. It asks for "instance of a class came from a Singleton" which is different from "instance of class Singleton" – Jonas Wilms Jul 11 '19 at 12:57
  • @JonasWilms, i dont' understand. a class can not come from a singleton, because the instance is the result of calling a singleton with `new`. what is the semanic content here, which may or may not op is questioning? – Nina Scholz Jul 11 '19 at 13:02
  • "Instanz der Singleton Klasse" vs. "Instanz einer Singleton Klasse" ... ersteres wird beantwortet, letzteres wurde gefragt (wenn ich die Frage nicht missverstehe) – Jonas Wilms Jul 11 '19 at 13:06
  • ok. right. then the instance of the constructor has to be checked (as you wrote). – Nina Scholz Jul 11 '19 at 13:09
  • `new singletonOrMaybeNo.constructor` what was I was looking for!! thanks @JonasWilms, because the issue is that even I don't know the name of the Singleton class! I mean I just have the instance, But the class Singleton could have any name! Thanks!!! – Ruben Saucedo Jul 11 '19 at 13:52
  • I just read your answer below and leave it a comment, Thanks @JonasWilms – Ruben Saucedo Jul 11 '19 at 14:04
2

The concept of a "singleton class" comes from languages that just have classes (Java for example), JavaScript however has much more than classes (objects, functions, "global code"), and therefore we don't need to mimic a singular object creation with a fake class, we can just do:

   const singleton = { some: 0, properties: 0 };
   // initialization goes here

You are right that it is possible to create a "singleton class", but that has no benefits, it just adds boilerplate, and, in my eyes, makes the code harder to follow (as I'd expect new Class to create an instance, and not to return a singleton).

To check wether an instance comes from a class that is written in your "singleton pattern way", you could simply check for the instance:

   instance === instance.constructor.instance

But I'm not sure wether that is useful at all. It's questionable wether you actually need those classes, and if you really need those, then you probably only have a few of them, and it would be way less error prone to check wether the instance is instanceof one of them:

  instance instanceof Singleton1 || instance instanceof Singleton2

If your "singleton class"es are not written by you, and you only know that they come from a constructor function that might return existing instances, then the only way would be to create a new instance of that class, and check wether the same instance was returned:

  instance === new instance.constructor

If the constructor however requires arguments then that will break, or if it's just a regular class instance you will create an unneccessary instance, which might cause unwanted side effects.

So after all: Why do you need that?

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 1
    I was checking a project that use a singleton patter for a database, just there is moment where I want to confirm that the pattern is correctly through all the project. I mean I could just leave it but I want to avoid future problems. Or if better change the strategy. :) Thanks – Ruben Saucedo Jul 11 '19 at 14:02
1

instanceof will return true if an object is an instance of a class:

class Singleton {
  constructor() {
    const instance = this.constructor.instance;
    if (instance) return instance;
    this.constructor.instance = this;
  }
}

let singletonOrMaybeNo = new Singleton();

console.log(singletonOrMaybeNo instanceof Singleton);
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
  • Why the downvote? This is a simple answer that works perfectly. – Jack Bashford Jul 11 '19 at 12:46
  • The constructor property is not reliable and *instanceof* doesn't work across frames. Plus the OP wants to determine if an object is a singleton, not simply an instance. – RobG Jul 11 '19 at 12:51
  • What frames @RobG? – Jack Bashford Jul 11 '19 at 12:51
  • The ones often used in web pages. – RobG Jul 11 '19 at 12:54
  • @robg a constructor check doesn't work either. Passing objects across frames is a hypothetical problem, that probably doesnt apply in this case. – Jonas Wilms Jul 11 '19 at 12:54
  • This does not answer the question. It asks for "instance of a class came from a Singleton" which is different from "instance of class Singleton" (thats my downvote, couldn't comment yet due to unreliable WiFi on the train) – Jonas Wilms Jul 11 '19 at 12:57
  • Not exactly sure what the difference is @JonasWilms (my lack of knowledge) - could you explain exactly what the difference is please? – Jack Bashford Jul 11 '19 at 13:00
  • `function OtherSingleton() { return instance; }`, `new OtherSingleton === new Singleton` is false. – Jonas Wilms Jul 11 '19 at 13:03
  • @JonasWilms—I haven't suggested that the constructor property does "work" in this case. I find it pretty useless. – RobG Jul 11 '19 at 13:04