Javascript对象分配'他奇怪的行为

Javascript object assignment's strange behavior

本文关键字:对象 分配 Javascript      更新时间:2023-09-26

我是javascript的新手(实际上是编程的新手)。我遇到了for/in循环的这种行为,我不太理解。以下几段代码是使用控制台中的$node命令运行的。

code_0:

var result = {};
var list = ['A', 'B', 'C'];
for(var index in list){
    var id = list[index];
    result[id] = {};
    result[id]['name'] = id;
}
console.log(result);

结果_0:

{ A: { name: 'A' }, B: { name: 'B' }, C: { name: 'C' } }

code_1:

var result = {};
var list = ['A', 'B', 'C'];
var INIT = {'a': 0, 'b': 0, 'c': 0,}
for(var index in list){
    var id = list[index];
    result[id] = INIT;
    result[id]['name'] = id;
}
console.log(result);

结果1:

{ A: { a: 0, b: 0, c: 0, name: 'C' },
  B: { a: 0, b: 0, c: 0, name: 'C' },
  C: { a: 0, b: 0, c: 0, name: 'C' } }

我能理解为什么code_0会给出result_0。但结果_1是我不明白的。我预计结果_1为:

{ A: { a: 0, b: 0, c: 0, name: 'A' },
  B: { a: 0, b: 0, c: 0, name: 'B' },
  C: { a: 0, b: 0, c: 0, name: 'C' } }

code_0和code_1之间有什么区别?为什么code_1会给出result_1?

编辑:*添加与问题相关的标签。*更改标题。(标题过去是关于循环的)

对象在Javascript中是通过引用(而不是复制)分配的。这是在第一次学习Javascript时混淆和学习的一个常见点。

在您的code_1块中,这行代码:

result[id] = INIT;

是在循环的每次迭代中为完全相同的对象指定一个引用,因此它们都指向相同的对象,并且都具有相同的属性(因为它们都是相同的对象)。因此,对result[id]的任何进一步更改实际上都只是对INIT的更改,INIT是result中所有插槽正在使用的同一对象,因此它们看起来都同时更改。

在Javascript中,如果您希望在每次分配中都有一个对象的单独副本,那么您必须在分配之前创建一个新对象。在最新的浏览器中,可以使用Object.assign()将可枚举属性从一个对象复制到另一个对象。

使用Object.assign(),有一种方法可以解决在分配对象之前复制对象的问题:

var result = {};
var list = ['A', 'B', 'C'];
var INIT = {'a': 0, 'b': 0, 'c': 0,}
for(var index in list){
    var id = list[index];
    // make a new object that is a copy of INIT
    var obj = Object.assign({}, INIT);
    obj.name = id;
    // put that new object into result[id]
    result[id] = obj;
}
console.log(result);

对于较旧的浏览器,这里有一个适用于Object.assign()的polyfill:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


这里有一个简单的例子:

 var items = {a:1, b:2, c:3};
 var list1 = items;
 var list2 = items;
 list1.a = 10;
 console.log(items);               // {a:10, b:2, c:3}
 console.log(list1);               // {a:10, b:2, c:3}
 console.log(list2);               // {a:10, b:2, c:3}
 console.log(list1 === items);     // true, they are the same object
 console.log(list2 === items);     // true, they are the same object

您可以看到,所有三个变量都显示相同的值,因为它们都指向完全相同的对象,因此通过三个变量中的任何一个修改对象都会产生完全相同的变化。