Javascript对象赋值的奇怪行为

时间:2015-12-31 04:06:01

标签: javascript node.js loops object assign

我是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);

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

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。但是result_1是我不明白的。我期望result_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?

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

1 个答案:

答案 0 :(得分:6)

在Javascript中通过引用(而不是通过副本)分配对象。这是第一次在Javascript中加速时混淆和学习的常见问题。

code_1块中,这行代码:

result[id] = INIT;

在循环的每次迭代中为完全相同的对象分配引用,因此它们都指向同一个对象并且都具有相同的属性(因为它们都是相同的对象)。因此,对result[id]的任何进一步更改实际上只是对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()的填充: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

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