2

I'm not sure how to explain this, and it is REALLY bothering me. It is messing up so much of my code. Anyway, here is basically what it is. Assume I have a variable that holds a struct with some values, say default settings:

var DefaultValues = {
    username: "cakeisajoke",
    this: "is some",
    default: {
        data: 483
    },
    lives: 3,
    playerX: 0,
    playerY: 0
}

In my code, I use this variable as a "template", so I can reset my game easier. Like this:

var GameValues = DefaultValues;

Okay, so that makes sense so far. Now, let's say the player loses lives:

GameValues.lives--;

Or, the player moves some:

GameValues.playerX += 20;
GameValues.playerY -= 10;

So, now my GameValues is changed, and I set the game to this. But, then the player fails, and gets a game over. If he wants to play again, all I have to do is reset the GameValues variable to the defaults:

GameValues = DefaultValues;

And, as far as I am concerned, this should just set GameValues to DefaultValues, right? But, it doesn't. For some reason, GameValues and DefaultValues now have the same values, when they shouldn't. For example, DefaultValues is now 0, instead of what is was originally, 1.

Why is it doing this? I have looked, and looked again, and I am NOT setting DefaultValues anywhere in the code except for that initial struct.

"I used this and default as an example, I know that I can't actually use them since they are reserved"

tshepang
  • 12,111
  • 21
  • 91
  • 136
pjrader1
  • 491
  • 7
  • 22

5 Answers5

1

This is because javascript uses references for objects. So assigning an object to another object just makes them point to the same object. You'll need to clone the object, this thread describes a few ways to do it.

var GameValues = DefaultValues; //Both variables reference the same object
GameValues.lives--; //Since they both reference the same object this will change both the variables so to say

Also consider not using the words this and default as keys, they are reserved keywords.

Community
  • 1
  • 1
Hugo Tunius
  • 2,869
  • 24
  • 32
1

Your current issue is because of javascript uses references for objects.

For this king of approach you can use other js patterns like this

var DefaultValues = {
    username: "cakeisajoke",
    "this" : "is some",
    default: {
        data: 483
    },
    lives: 3,
    playerX: 0,
    playerY: 0
}

var GameValues =  Object.create(DefaultValues);

and you can do

GameValues.lives--;
GameValues.playerX += 20;
GameValues.playerY -= 10;

with out changing the defalut.

Its worth to have a look at this modeling-patterns-for-javascript-browserbased-games

Community
  • 1
  • 1
Sarath
  • 9,030
  • 11
  • 51
  • 84
  • `Object.create` isn't supported in some older browsers, this should be checked and handled if you are going to use it. – Hugo Tunius Nov 11 '13 at 08:27
1

When you create your DefaultValues object, you create an object in memory, and a reference to that object which is in your DefaultValues variable:

+---------------+                +-------------------------+
| DefaultValues |--------------->| username: "cakeisajoke" |
+---------------+                | lives:    3             |
                                 | (and so on)             |
                                 +-------------------------+

when you do this:

var GameValues = DefaultValues;

you're just storing the reference to the object in a second variable. Now you have this:

+---------------+
| DefaultValues |---+
+---------------+   |            +-------------------------+
                    |            | username: "cakeisajoke" |
                    +----------->| lives:    3             |
                    |            | (and so on)             |
+---------------+   |            +-------------------------+
| GameValues    |---+
+---------------+

You don't have a copy of DefaultValues, you just have two references to the object. Changes you make to the object change the object, and so naturally are visible regardless of which reference you use.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

When you do assignment var a = {}, JavaScript stores in a reference to newly created object, not its value, that's why when you change settings via GameValues, settings in DefaultValues are also changing: those two are the references to the same object.

When you initialize new variable of primitive type, such as var i = 1;, it stores in i the actual value so

var i = 1;
var b = i;
var b += 4; // b is 5, i is still 1   

To solve your particular task you can write a recursive function which will traverse the object, and make a copy of every key-value pair. See this article, it should provide you some insights on how to do it.

aga
  • 27,954
  • 13
  • 86
  • 121
0

Because DefaultValues is an object, when you assign it to GameValues you are actually just assigning a reference to it, rather than copying the object itself. That means when you set a property of one, the change will be reflected in the other.

You could work around that by copying the properties from DefaultValue onto GameValue instead of doing it in one assignment. Here's a basic example of that, but note that you'd have to handle nested objects too:

Object.keys(DefaultValues).forEach(function (key) {
    GameValues[key] = DefaultValues[key];
});
James Allardice
  • 164,175
  • 21
  • 332
  • 312