繁体   English   中英

为什么Javascript中的嵌套对象不保留其值?

[英]Why don't nested objects in Javascript preserve their values?

我正在运行两个测试,以检查对象在javascript中的工作方式:

测试一个:

 //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)); 

结果是:

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

您可以看到通过创建player2更改了player1的动作对象。

如果我希望操作对象保留其价值怎么办?

我能想到的唯一方法是:

 //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)); 

在这种情况下,输出为:

{"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"}}

有什么更好的方法可以使用方法1,但不更改操作对象?

有什么更好的方法可以使用方法1,但不更改操作对象?

使用构造函数为您初始化action属性,这样您就不必手动将其写出。 您无法避免需要它们 ,除非将它们弄平并将.action*直接放在播放器上。

因为当您在Javascript中替换数组或对象时,Javascript会引用数组/对象而不是复制。 因此,当您执行player1.action.action1 = "aaa"; player2.action.action1 = "bbb"; ,您正在更改Player的值。 由于玩家1或玩家2只是指向Player对象。

Object.create()方法使用指定的原型对象和属性创建一个新对象。

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

这意味着您正在创建一个对数组/对象具有相同引用的新对象。 因为甚至Player都没有Array作为其属性,而是对Array / Object的内存地址的引用,所以Object.create()创建的新Object也只有引用。

如果同时检查“播放器”对象的内容,则会注意到其值也已更改。

console.log(Player)

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

为了避免这种情况。 将对象用作原型时,需要深度复制该对象。

//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)

你需要jQuery

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

这为您提供了完美的深度复制对象。 并且上面的代码按预期工作。

请在此处查看jQuery.extend详细信息http://api.jquery.com/jquery.extend/

这里的问题是两个播放Player都共享与原型相同的Player对象。 当一个玩家更改了该对象中的字段时,当寻找另一个对象时,它们也会被更改。

您可以为此使用构造函数:

// 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));

当您调用new Player() ,将实例化一个新对象,并为此对象创建新属性,例如nameid ,并且Player多个实例不会彼此冲突。

Object.create作用是,将一个对象作为输入,并将其所有属性复制到新对象。 现在,如果属性指向可变值,则可以使用新创建的对象对其进行突变。 因此,您可以使用Player.action中指向它的值的任何引用变量, player1.actionplayer2.actionplayer1.action player2.action的值。

并且根据您的代码, Player应该是类而不是对象。 因此,我们可以使它成为一个构造函数(JS没有类,但是有对象构造函数),如下所示。

//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));

在这里,对象player1player2是使用构造函数Player创建的。 new关键字实际上启动了一个新对象。 从传统的OOP角度讲,您可以说Player类的player1player2对象是使用new关键字创建的。

输出将是

{"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"}}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM