1

I am running two tests to check how objects worked in javascript:

Tests one:

//Method 1
var Player = {

  name: "",
  id: "",
  action: {
    action1: "",
    action2: "",
    action3: ""
  }
}

var player1 = Object.create(Player);
player1.name = " hack";
player1.id = 1;
player1.action.action1 = "aaa";
player1.action.action2 = "aaa";
player1.action.action3 = "aaa";
console.log(JSON.stringify(player1.action));

var player2 = Object.create(Player);
player2.name = " Jason";
player2.id = 2;
player2.action.action1 = "bbb";
player2.action.action2 = "bbb";
player2.action.action3 = "bbb";

console.log(JSON.stringify(player2.action));
console.log(JSON.stringify(player1.action));

The result is:

          {"action1":"aaa","action2":"aaa","action3":"aaa"}
 VM174:29 {"action1":"bbb","action2":"bbb","action3":"bbb"}
 VM174:30 {"action1":"bbb","action2":"bbb","action3":"bbb"}

you can see the action object of player1 had been changed by creating player2.

What if I want the action object preserve it's value?

The only way I can think about is following:

//Medthod 2 
var actionManager = {

  action1: "",
  action2: "",
  action3: ""

}
var Player = {

  name: "",
  id: "",
  action: null
}

var player1 = Object.create(Player);
var actions1 = Object.create(actionManager);
actions1.action1 = "aaa";
actions1.action2 = "aaa";
actions1.action3 = "aaa";

player1.name = " hack";
player1.id = 1;
player1.action = actions1;
console.log(JSON.stringify(player1));
var player2 = Object.create(Player);
player2.name = " Jason";
player2.id = 2;

var actions2 = Object.create(actionManager);
actions2.action1 = "bbb";
actions2.action2 = "bbb";
actions2.action3 = "bbb";

player2.action = actions2;
console.log(JSON.stringify(player2));
console.log(JSON.stringify(player1));

In this case the output is:

{"name":"hack","id":1,"action:{"action1":"aaa","action2":"aaa","action3":"aaa"}} 

{"name":" Jason","id":2,"action:{"action1":"bbb","action2":"bbb","action3":"bbb"}}

{"name":" hack","id":1,"action":{"action1":"aaa","action2":"aaa","action3":"aaa"}}

Is there any better way to use Method 1 but make the action object not being changed?

t.niese
  • 39,256
  • 9
  • 74
  • 101
JavaScripter
  • 4,282
  • 9
  • 37
  • 45
  • That is because the Object stored for `action` is for both elements the same. `Object.create(Player);` does (not fully technical correct explanation, but the same problem) not do a deep copy but a shallow copy. – t.niese Feb 17 '15 at 07:19

4 Answers4

0

Is there any better way to use Method 1 but make the action object not being changed?

Use a constructor function that initialises the action property for you, so that you don't have to write it out manually. You cannot avoid needing them, except you flatten them and put the .action*s directly on the player.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Since When you substitute Array or Object in Javascript, Javascript makes Referencing to the Array/Object instead of Copying. So when you do player1.action.action1 = "aaa"; or player2.action.action1 = "bbb";, You are changing the Value of Player's value. Since player1 or player2 are just pointing to Player Object.

The Object.create() method creates a new object with the specified prototype object and properties.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

which means you are creating a new object which has same reference to the Array/Object. Because even Player does not have Array as its property but a reference to the memory address of the Array/Object.So the new Object created by Object.create() also have just references.

If you check What the Player object has as well, You'd notice that its values had also changed.

console.log(Player)

action:
  action1: "bbb"
  action2: "bbb"
  action3: "bbb"

To avoid this. You need to deep copy the object when you use it as prototype.

//Method 1
var Player = {

  name: "",
  id: "",
  action: {
    action1: "",
    action2: "",
    action3: ""
  }
}

objectCreate = function(obj){
    return jQuery.extend(true, {},obj)
};

var player1 = objectCreate(Player);
player1.name = " hack";
player1.id = 1;
player1.action.action1 = "aaa";
player1.action.action2 = "aaa";
player1.action.action3 = "aaa";
console.log(JSON.stringify(player1.action));

var player2 = objectCreate(Player);
player2.name = " Jason";
player2.id = 2;
player2.action.action1 = "bbb";
player2.action.action2 = "bbb";
player2.action.action3 = "bbb";

console.log(JSON.stringify(player2));
console.log(JSON.stringify(player1));
console.log(Player)

You need jQuery though

objectCreate = function(obj){
    return jQuery.extend(true, {},obj)
};

this gives you perfect deep copied Object. and the code above works as you expected.

see the jQuery.extend details here http://api.jquery.com/jquery.extend/

suish
  • 3,253
  • 1
  • 15
  • 34
0

The problem here is that both players share the same Player object as prototype. When one player alters fields in this object, they will be changed when looking in the other object too.

You can use constructor functions for this:

// constructor function
function Player () {
  this.name = "";
  this.id = "";
  this.action = {
    action1: "",
    action2: "",
    action3: ""
  };
}

var player1 = new Player();
player1.name = " hack";
player1.id = 1;
player1.action.action1 = "aaa";
player1.action.action2 = "aaa";
player1.action.action3 = "aaa";
console.log(JSON.stringify(player1.action));

var player2 = new Player();
player2.name = " Jason";
player2.id = 2;
player2.action.action1 = "bbb";
player2.action.action2 = "bbb";
player2.action.action3 = "bbb";

console.log(JSON.stringify(player2.action));
console.log(JSON.stringify(player1.action));

when you call new Player(), a new object is instantiated, and new properties like name and id are created for this object, and multiple instances of Player will not conflict with each other.

Jos de Jong
  • 6,602
  • 3
  • 38
  • 58
0

What Object.create does is, it take an object as the input and copies all it's attributes to the new object. Now if a attribute points to a mutable value you would be able to mutate it using the newly created object. So, you can mutate the value of Player.action using any reference variable that points to it's value, player1.action and player2.action in your example.

And according you code Player should a class instead of an object. So, we can make it a constructor function (JS don't have classes but have object constructors) as follows.

//New Method 1
var Player = function() {
  this.name = "";
  this.id = "";
  this.action = {
    action1: "",
    action2: "",
    action3: ""
  };
};

var player1 = new Player();  // Create a new object using `Player` constructor function
player1.name = " hack";
player1.id = 1;
player1.action.action1 = "aaa";
player1.action.action2 = "aaa";
player1.action.action3 = "aaa";
console.log(JSON.stringify(player1.action));

var player2 = new Player();  // Create another object using `Player` constructor function
player2.name = " Jason";
player2.id = 2;
player2.action.action1 = "bbb";
player2.action.action2 = "bbb";
player2.action.action3 = "bbb";

console.log(JSON.stringify(player2.action));
console.log(JSON.stringify(player1.action));

Here objects player1 and player2 are created using constructor Player. The new keyword actually initiates a new object. In conventional OOP's sense you can say player1 and player2 objects of class Player have been created using the new keyword.

And the output would be

{"name":"hack","id":1,"action":{"action1":"aaa","action2":"aaa","action3":"aaa"}} 

{"name":" Jason","id":2,"action":{"action1":"bbb","action2":"bbb","action3":"bbb"}}

{"name":" hack","id":1,"action":{"action1":"aaa","action2":"aaa","action3":"aaa"}}
Debanshu Kundu
  • 785
  • 7
  • 18