Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Semantic JavaScript singleton with constructor

So I'd like to have a class called client which will be the base of a video game I'm writing in JavaScript.

client should be a class that there can only be one instance of, but its first creation should be set by myself at a specific event, like when the user clicks the "start" button.

I made myself a singleton class and I'm starting it unload just for testing:

// Singleton class for the client
var client = (function() {

  // Public methods
  var _this = {
    construct: function() {
      delete _this.construct;
      _this.director = new lime.Director(document.body, window.innerWidth, window.innerHeight); // Setup the rendering engine
    }
  }
  return _this;
})();

// Fire when dependencies are loaded
window.onload = client.construct;

The problem:

But I intend for this to be an open source project and on the last line client.construct seems to be a highly unusual convention. How can I write my singleton class so that it will be constructed with new Client and can never be constructed again?

like image 360
alt Avatar asked Aug 25 '26 09:08

alt


2 Answers

Firstly: are you sure you really want to do this? For most simple cases, you're probably better off not bothering with a prototype or using the new keyword at all, and instead just writing an object literal with the properties and methods you want - or creating an object with a one-off function if slightly more complicated construction logic is required. Simplicity is good.

I guess there are a couple of situations in which you might want to create a 'traditional' singleton in JavaScript, though - like to delay instantiation, or if you're using classical inheritance involving your singleton class's prototype.

In that case, you might want to try this approach, based upon bfavaretto's, in which the user of the class is expected to get a Client object by calling Client.getSingletonInstance() instead of new Client(), and the instantiation of a Client via new happens inside the getSingletonInstance() method.

var Client = (function() {
    // Our "private" instance
    var instance;

    // The constructor
    function Client() {

        // If it's being called again, throw an error
        if (typeof instance != "undefined") {
            throw new Error("Client can only be instantiated once.");
        }

        // initialize here

        // Keep a closured reference to the instance
        instance = this;
    }

    // Add public methods to Client.prototype
    Client.prototype.myPublic = function() {

    }

    Client.getSingletonInstance = function() {
        if (typeof instance == "undefined") {
            return new this();
        }
        else {
            return instance;
        }
    }

    // Return the constructor
    return Client;
})();


var c1 = Client.getSingletonInstance();
var c2 = Client.getSingletonInstance();

console.log(c1 == c2); // true

I prefer this way, because it seems to me that having the user of the class call new but not actually get a new object is misleading.

http://jsfiddle.net/hBvSZ/3/

like image 64
Mark Amery Avatar answered Aug 26 '26 21:08

Mark Amery


You can use the same pattern you would use in a regular object-oriented language: store the instance in a "private" or "static" property (I'm quoting those terms because they don't precisely apply to JavaScript). In code, that would be something like this, using a "private" property to store the instance (a "static" property would be a property of the constructor):

var Client = (function() {
    // Our "private" instance
    var instance;

    // The constructor
    function Client() {

        // If it's being called again, return the singleton instance
        if(typeof instance != "undefined") return instance;

        // initialize here

        // Keep a closured reference to the instance
        instance = this;
    }

    // Add public methods to Client.prototype
    Client.prototype.myPublic = function() {

    }

    // Return the constructor
    return Client;
})();


var c1 = new Client();
var c2 = new Client();

console.log(c1 == c2); // true

http://jsfiddle.net/hBvSZ/

like image 45
bfavaretto Avatar answered Aug 26 '26 23:08

bfavaretto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!