4

I have a question about JavaScript. I'm currently using code similar to the code below:

function Game() {

}

I want to nest objects, so I can access them like so:

var a = new Game();
a.nested_object.method();
a.nested_object.property;

How would I go about doing this? Would I use a function or {}? Or does it even matter? The code below is an example code of what I am referring to.

function Game() {

this.id;

var stats = {};

}

Like I've stated above, can I access stats like so:

var a = new Game();
a.stats
JaPerk14
  • 1,664
  • 3
  • 24
  • 32

6 Answers6

6

I would do this:

function Game() {
    this.id;
    this.stats = new Stats(this);
}

function Stats(game) {
    this.property;
    this.method = method;

    function method() {
        this.property;
        game.id;
    }
}

var game = new Game;
game.stats.method();

The reasons are as follows:

  1. Separation of concerns - the game constructor can concentrate entirely on the game logic and the stats constructor will concentrate only on the statistics of the game.
  2. Modularity - You can put the game constructor and the stats constructor in two different files. This allows you to deal with them separately and makes the project easier to manage.
  3. Loose Coupling - The stats object doesn't need to know about the game object. So it's better to separate it from the game object. If you create it using an object literal notation instead (as @Bergi did) then the stats object has access to the private members of the game object (which could be counter-productive if the stats object accidently changes a private property of the game object).
  4. Readability - Compare @Bergi's code and mine. Separating the stats and the game object makes the code easier to read and understand. You can have one glance at the code and know exactly what's going on.
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
2

Yes, that's exactly the way to go.

Notice that the this keyword in your method() will hold the nested_object, not your Game instance. You can get a reference to that only by using a variable pointing to:

function Game() {
    var that = this; // the Game instance
    this.id = …;
    this.nested_object = {
        property: "nested!",
        method: function() {
            this.property; // nested! (=== that.nested_object.property)
            that.id // the game property
        }
    };
}
var game = new Game;
game.nested_object.method();

Because of that nested objects on the prototype (where you don't have a variable containing the instance) will seldom make much sense - see Crockford's Prototypal inheritance - Issues with nested objects.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • What's the purpose of "var that = this"? I see the variable declared, but never used. – JaPerk14 Jan 11 '13 at 01:42
  • Note that `var message = "hello"; this.nested_primitive = message;` will create a copy, not an object reference… – Potatoswatter Jan 11 '13 at 01:49
  • @Potatoswatter: "nested_primitive" doesn't make much sense to me. What exactly do you mean? – Bergi Jan 11 '13 at 01:52
  • @Bergi Changing the value through `this` or `game` won't affect the `var` for a primitive object. The pattern with `nested_object` only works with proper Objects, which may be unintuitive for a newcomer. (You've sort-of addressed this in another [answer](http://stackoverflow.com/a/10131255/153285).) – Potatoswatter Jan 11 '13 at 01:55
  • @Potatoswatter: There is no such thing as "primitive object". Both `this` (at least in here) and `game` are proper objects. – Bergi Jan 11 '13 at 02:55
  • @Bergi Yes, even with a little more experience I forget that object references are equally primitive to integers. Anyway, the getter/setter idiom works well to avoid confusion when `object.property = something;` is attempted. Why not recommend that here, as in your other answer? – Potatoswatter Jan 11 '13 at 02:59
0

Add the "nested" stuff to this or to Game.prototype.

ericponto
  • 736
  • 4
  • 8
  • Beware from `Game.prototype` if you don't know what you are doing. Do not advertise this option without the appropriate warning. – Bergi Jan 11 '13 at 01:39
  • I agree. Using prototype is a little bit harder to understand than just using `this`. – ericponto Jan 11 '13 at 01:47
  • It would be OK as well, but nested objects on the prototype have a different behaviour - that's what you need to be aware of – Bergi Jan 11 '13 at 01:49
0

[Edited to respond to comments below]

How about this:

function Game() {

    this.nested_object = {
        method: function () {
            return 'method return value';
        },

        property: 'property value'
    };

};

var a = new Game();
alert( a.nested_object.method() );
alert( a.nested_object.property );
Eamonn O'Brien-Strain
  • 3,352
  • 1
  • 23
  • 33
0

Just create the nested object in the constructor.

function Game() {
    this.stats = { lives: 3 };
};

var a = new Game();
-- a.stats.lives;

However, this can be annoying as in the implementation of Game you must refer to stats as this.stats. The this'es add up and confusion can arise when this refers to the wrong thing, for example inside a function(){} expression.

My preferred pattern looks like this. It's essentially a classic OO getter function.

function Game() {
    var stats = { lives: 3 };
    this.stats = function() { return stats; };
};

var a = new Game();
-- a.stats().lives;
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • What's the difference between "var stats" and "this.stats"? I keep thinking that one should overwrite the other's value. Is this not how it works? – JaPerk14 Jan 11 '13 at 01:40
  • @JaPerk14: No. See [Javascript: Do I need to put this.var for every variable in an object?](http://stackoverflow.com/questions/13418669/javascript-do-i-need-to-put-this-var-for-every-variable-in-an-object/13418980#13418980) – Bergi Jan 11 '13 at 01:43
  • @JaPerk14 Nope, two completely different variables. If `this.stats` exists but you write `stats.lives = 3;`, that's an error. Creating `var stats` doesn't add anything to `this`. – Potatoswatter Jan 11 '13 at 01:43
  • @Bergi Awesome, I came up with it independently but it's nice to see a reference that calls the getters "clever" :) – Potatoswatter Jan 11 '13 at 01:45
0

This should be more appropriate

function Game() {
  this.id;
  this.stats = "Hello";
  return this;
}

var a = new Game();
alert(a.stats);

Basically in your case stats is a local variable , and the object created has no idea about the variable.

Check Fiddle

Sushanth --
  • 55,259
  • 9
  • 66
  • 105