为什么 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"}
您可以看到玩家 1 的动作对象已通过创建玩家 2 而更改。
如果我希望动作对象保留其值,该怎么办?
我能想到的唯一方法是:
//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 但使操作对象不被更改?
这里的问题是两个玩家共享与原型相同的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()
时,将实例化一个新对象,并为该对象创建 name
和 id
等新属性,并且Player
的多个实例不会相互冲突。
有没有更好的方法来使用方法 1 但使操作对象不被更改?
使用为您初始化 action
属性的构造函数,这样您就不必手动将其写出。你无法避免需要它们,除非你把它们放平,把.action*
直接放在播放器上。
因为当你在Javascript中替换Array或Object时,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 作为其属性,而是对数组/对象的内存地址的引用。所以Object.create()
创建的新对象也只有引用。
如果同时选中 Player 对象具有什么,则会注意到其值也发生了更改。
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/
Object.create
所做的是,它将一个对象作为输入,并将其所有属性复制到新对象。现在,如果属性指向可变值,则可以使用新创建的对象对其进行更改。因此,您可以使用任何指向Player.action
的值、player1.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));
这里对象player1
和player2
是使用构造函数Player
创建的。new
关键字实际上启动了一个新对象。在传统的 OOP 意义上,你可以说类 Player
的player1
和player2
对象都是使用 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"}}
- 如何设置类型化对象的属性,同时保留它's类型
- 如何在发布JavaScript日期对象时保留时区偏移量
- Javascript扩展对象's原型,但保留旧原型
- 为什么 Javascript 中的嵌套对象不保留它们的值
- 我应该如何保留对'options对象'在ES6实例中
- javascript对象,连接重复的键,同时保留多个值
- 比较两个数组,并通过使用 javascript 保留现有对象来更新新值
- Javascript:如何在混合原始对象后保留定义的对象描述符
- Javascript对象保留包含旧数据
- 下划线,清除对象的所有值,但保留键
- 将对象分配给另一个对象并保留原始数据
- 如何从新对象返回值,同时保留其方法
- 按字母顺序排列 AngularJS 中对象保留键/值关联的选项
- Javascript子类对象不保留基类的属性/方法
- ThreeJS - 始终将对象保留在摄像机视图中
- 将两个或多个 JSON 对象数组合并为一个数组,保留唯一性
- 是否可以在JS中获取保留字(变量,函数,对象名称)的列表
- 有没有办法初始化保留初始 HTML 的 Vue 对象
- 在Javascript中保留对象数组排序后的插入顺序
- 在JavaScript中保留对象的状态将其转换为文本,可以作为参数(作为对象)传递给另一个函数