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

6 Answers 6

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.
Sign up to request clarification or add additional context in comments.

Comments

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.

6 Comments

What's the purpose of "var that = this"? I see the variable declared, but never used.
Note that var message = "hello"; this.nested_primitive = message; will create a copy, not an object reference…
@Potatoswatter: "nested_primitive" doesn't make much sense to me. What exactly do you mean?
@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.)
@Potatoswatter: There is no such thing as "primitive object". Both this (at least in here) and game are proper objects.
|
0

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

3 Comments

Beware from Game.prototype if you don't know what you are doing. Do not advertise this option without the appropriate warning.
I agree. Using prototype is a little bit harder to understand than just using this.
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
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;

4 Comments

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 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.
@Bergi Awesome, I came up with it independently but it's nice to see a reference that calls the getters "clever" :)
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 );

3 Comments

What is the return statement for?
@JaPerk14 If you return a value from a constructor, it overrides the default behavior of returning this, and as a result prototype isn't used.
Thanks @JaPerk14 I hadn't noticed it was being called with "new". (I usually use a more functional style and avoid using new,) I changed the code above.
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

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.