3

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?

1

6 Answers 6

7

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/

Sign up to request clarification or add additional context in comments.

Comments

3

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/

Comments

1

Something like this:

var Client = (function ClientClass(){

  var instance;

  // Constructor
  function Client() {
    if (instance) throw 'Already instantiated';
    this.director = new lime.Director(...);
    instance = true;
  }

  Client.prototype = {
    // Public methods
  };

  return Client;

}());

4 Comments

When I saw your answer, I almost threw mine away. They're very similar, the difference is you're throwing an error, while I'm returning the instance if there is one already.
+1, but it seems to me that what's missing from both your answers is some kind of Client.getSingletonInstance() method which creates and returns a new instance if none has been created, and returns the existing one otherwise. Isn't that basically the point of the singleton pattern? To have the user of the class use a static method to get their instance rather than call new, yet always get the same instance?
@MarkAmery: Well, that's what bfavaretto's answer does right but with the constructor? It all depends on if you want to allow calling the constructor more than once or not.
@elclanrs See my answer for what I mean. Basically, it's shifting what the user of the class would do using 'new' in bfavaretto's case to being done via something simulating a 'static method' instead, and throwing an error if the user of the class tries to instantiate it a second time with new. I think this keeps the best of both your approaches.
0

This may be what you want:

var initialized = false;

function initialize() {
    if (!initialized) {
        window.client = new Client();
        initialized = true;
    }
}

window.onload = initialize;

Comments

0

You don't. In strongly-typed languages, singletons are made by having private constructors and exposing a static property that contains the only instance of the class. The only thing you may do to prevent instantiating a second time is to throw exceptions but that is even poorer design. You may however delay instantiating your object:

// A wrapper function
var client = (function () {
    var client = function() {
       // Actual class
    }
    var instance = null;
    // Property to return the instance
    Object.defineProperty("instance", {
        get: function () {
            if (!instance) { instance = new client(); }
            return instance;
        }
    }
   return client;
})();

Comments

0

This is my favorite pattern for singleton instance, it is simple and straightforward:

var mySingleton = new function() {
    // ...
}

So you can do:

var myClient = new function() {
    this.director = null;
    this.initialize = function() {
        // Setup the rendering engine
        this.director = new lime.Director(
            document.body, 
            window.innerWidth, 
            window.innerHeight
        );
    }
}

window.onload = myClient.initialize();

Source: Singleton pattern by Alexander Podgorny

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.