数组填充为什么会重复使用相同的对象?

12

var arr = new Array(4).fill({});

arr[2].status = true;

console.log(arr[0].status); 

为什么Array.fill在所有索引中填充相同的对象?


6
因为你将相同的对象插入到数组中的每个单元格。 - Sirko
1
如果你希望每个项目都有一个新的对象,请使用 Array.from({length: 4}, () => {}) - loganfsmyth
为什么数组填充在所有索引中都填充相同的对象?这就像问“为什么console.log('hello')会记录hello”。我不明白你的困惑。 - a better oliver
2个回答

14

.fill会在数组的每个部分中插入相同的对象(相同实例)。
这就是为什么执行.fill(Math.random)将返回填充了相同数字的数组。

你可以采用以下方法获得你想要的结果:

new Array(4).fill().map(() => ({}));

为了解释您问题代码的底层运作原理,让我们将其转换为ES5代码:

var arr = new Array(4);  // new Array(4)
var obj = new Object();  // *1: with this object instance
for(i = 0; i < 4; i++) { // .fill( *1 )
  arr[i] = obj;
}

正如你所看到的,我们正在将相同的对象实例 (obj) 分配给数组实例的每个单元格。

这是为什么的相同原理:

const obj = {};
const a = obj;
const b = obj;

a.foo = true;

使a.foo === b.foo的解析结果为true


1
fill 也是 ES2015 的一部分,而不是 ES5。 - Andrés Andrade
1
是的,那个有效,+1。请添加这个想法:该值是一个对象引用,每个项都是一个引用。 - Mihai Alexandru-Ionut
2
我真的很喜欢“解释发生了什么......” 注意:var obj = new Object(); {}不是新的,ES5版本中没有理由使用new Object()而不是{} - T.J. Crowder
我认为这更好地表达了“新实例被创建”的概念。 - Fez Vrasta
@AbdulGafarOlamideAjao 你肯定是在指 TypeScript,你可以直接传递 undefined 给它,让它高兴起来。 - Fez Vrasta
显示剩余2条评论

11
fill函数会重复填充传递给它的value,在这种情况下,value是一个对象引用。每个引用的副本都指向同一个对象,所以你得到的是:

       +−−−−−−−−−+
arr−−−>| (array) |
       +−−−−−−−−−+         +−−−−−−−−−−−−−−+
       | 0       |−−+−+−+−>|   (object)   |
       | 1       |−/ / /   +−−−−−−−−−−−−−−+
       | 2       |−−/ /    | status: true |
       | 3       |−−−/     +−−−−−−−−−−−−−−+
       +−−−−−−−−−+       

如果您想要单独的对象,则需要创建多个对象。当然,最简单的方法是:

var arr = [{}, {}, {}, {}];

示例:

var arr = [{}, {}, {}, {}];
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

如果你想使用可变长度进行操作:

由于你正在使用 Array.fill,我假设你正在使用ES2015(又称“ES6”)功能(但请参阅下面的ES5兼容解决方案而不需要填充)。你可以通过带有回调的 Array.from 来实现:

const arr = Array.from({length:4}, () => ({})); 
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

这将为您提供:

                    
       +−−−−−−−−−+       
arr−−−>| (数组) |       
       +−−−−−−−−−+         +−−−−−−−−−−−−−−+
       | 0       |−−−−−−−−>|   (对象)   |
       | 1       |−−−−−+   +−−−−−−−−−−−−−−+
       | 2       |−−−+ |   
       | 3       |−+ | |   +−−−−−−−−−−−−−−+
       +−−−−−−−−−+ | | +−−>|   (对象)   |
                   | |     +−−−−−−−−−−−−−−+
                   | |     
                   | |     +−−−−−−−−−−−−−−+
                   | +−−−−>|   (对象)   |
                   |       +−−−−−−−−−−−−−−+
                   |       | 状态: true |
                   |       +−−−−−−−−−−−−−−+
                   |                      
                   |       +−−−−−−−−−−−−−−+
                   +−−−−−−>|   (对象)   |
                            +−−−−−−−−−−−−−−+

在ES5中,如果您需要一个可变长度的变量,最简单的方法可能只是使用循环:

var arr = [];
for (var i = 0; i < 4; ++i) {
    arr[i] = {};
}
arr[2].status = true;
console.log("arr[0].status", arr[0].status);
console.log("arr[2].status", arr[2].status);

当然,你可以将它放入一个帮助函数中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接