由Array.prototype.fill()填充的数组的奇怪行为

时间:2016-12-13 13:09:44

标签: javascript arrays

我面对一些我不理解的数组。实际上,我创建了一个我用空子数组填充的数组来获得2D矩阵。 但是当我操纵数组时,它的行为并不像我预期的那样。

var arr = new Array(5);
arr.fill([]);
arr[2].push("third rank item");
console.log(arr);

//[ [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ],
//  [ 'third rank item' ] ]

欢迎这件事的每一个亮点

7 个答案:

答案 0 :(得分:7)

这与数组(以及通常的对象)是引用而不是值是一样的老问题。

具体来说,当您执行arr.fill([])时,您将获取一个空的数组并使用它来填充父数组。

就像说:

var arr = new Array(5);
arr[0] = arr[1] = arr[2] = arr[3] = arr[4] = [];

它们都引用相同的数组!所以当你继续修改其中一个时,看起来它们都被修改了(但实际上它仍然是相同的)

不幸的是,没有简单的方法为每个人分配一个空数组。你可以这样做:

Array.apply(null, Array(5)).map(function() {return [];});

基本上,创建一个长度为5的(初始化的)空数组,并将每个(空)值映射到新的[]

编辑:好像我以前被困住了。根据@ torazaburo的评论,您可以使用Array.from代替Array.apply(null, Array(5)).map,如下所示:

Array.from( new Array(5), function() { return []; } );

答案 1 :(得分:2)

Array.prototype.fill的ECMA doc的第11行显然给出了神秘的原因。

  

重复,而k <最终

     

设Pk为ToString(k)。

     

设setStatus(O,Pk,value,true)。

     

ReturnIfAbrupt(setStatus)。

     

将k增加1。

这里“价值”只是收到的参考。他们将它设置为直接排列的属性。这意味着所有填充的数组只是对单个数组对象的引用。

答案 2 :(得分:1)

正如您可以注意到使用array.fill,您将使用对同一数组的引用来填充数组,

如果要将每个数组索引实例化为空数组,则正常的while循环将执行:

&#13;
&#13;
var arr = [];
var n = 5
while(n--)
  arr[n] = []

arr[2].push("third rank item");
console.log(arr);
&#13;
&#13;
&#13;

选项2:
如果你有lodash包可用,你也可以使用_.map,因为这是专门设计来循环一个稀疏数组(原生地图将跳过非初始值)

&#13;
&#13;
var arr =_.map(new Array(5), (x => []))

arr[2].push("third rank item");
console.log(arr)
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

它发生了引用的原因。数组是一种对象,当你用[] or new Array()只填充运行数组填充你的数组时,对象就会对它们的引用起作用,并在所有索引中放入相同的数组,这就是为什么当你更新子数组时更新。

解决方案:

let arr = new Array(5).fill(0).map(ele => ele = []); arr[2].push("something");

OR

let arr = Array.of([], [], [], []); arr[2].push("something");

结果:正如预期的那样,只更新了arr的2个索引。

答案 4 :(得分:0)

你可以试试这个,

&#13;
&#13;
var arr = new Array(5);
var i = 0;
while (i < arr.length)
  arr.fill([], i++);
arr[2].push("third rank item");
console.log(arr);
&#13;
&#13;
&#13;

答案 5 :(得分:0)

试试这个,这是一行中的快速解决方案。

var arr = new Array(5);
arr = Array.from(arr, x => []);
arr[2].push("third rank item");
console.log(arr);

答案 6 :(得分:0)

对于ES6,我建议使用此方法来创建2个或多维数组:

// create an M x N dimension grid and fill it with 0's
const myArray = [...Array(M)].map(r => [...Array(N)].map(r => 0));