简体   繁体   English

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

[英]Strange behavior of an array filled by Array.prototype.fill()

I face something I don't understand with an array. 我面对一些我不理解的阵列。 Indeed, I created an array I have filled with empty subArrays to obtain a 2D Matrix. 实际上,我创建了一个我用空子数组填充的数组来获得2D矩阵。 But when I manipulate the array it doesn't behave as I expected. 但是当我操纵数组时,它的行为并不像我预期的那样。

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' ] ]

Every lights on this matter will be welcomed 关于此事的每一个亮点都会受到欢迎

This is the same old problem with arrays (and objects in general) being references rather than values. 这与数组(以及通常的对象)是引用而不是值是同样的老问题。

Specifically, when you do arr.fill([]) , you are taking that one single empty array and using that to fill the parent one. 具体来说,当您执行arr.fill([]) ,您将获取一个单个空数组并使用它来填充父数组。

It's like saying: 这就像说:

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

They all refer to the same array! 它们都引用相同的数组! So when you then go on to modify one of them, it looks like they're all modified (but really it's still the same one) 所以当你继续修改其中一个时,看起来它们都被修改了(但实际上它仍然是相同的)

Unfortunately there's no simple way to assign an empty array to each one. 不幸的是,没有简单的方法为每个人分配一个空数组。 You could do something like: 你可以这样做:

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

Essentially, create an (initialised) empty array of length 5 and map each (empty) value to a new [] . 实质上,创建一个长度为5的(初始化的)空数组,并将每个(空)值映射到新的[]

EDIT: Seems like I'm stuck in old times. 编辑:好像我以前被困住了。 As per @torazaburo's comment, you can use Array.from instead of Array.apply(null, Array(5)).map , like so: 根据@ torazaburo的评论,您可以使用Array.from而不是Array.apply(null, Array(5)).map ,如下所示:

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

The eleventh line of the ECMA doc of Array.prototype.fill is clearly giving the reason for the mystery. ECMA的Array.prototype.fill 文档的第11行显然给出了神秘的原因。

Repeat, while k < final 重复,而k <最终

Let Pk be ToString(k). 设Pk为ToString(k)。

Let setStatus be Set(O, Pk, value, true). 设setStatus为Set(O,Pk,value,true)。

ReturnIfAbrupt(setStatus). ReturnIfAbrupt(setStatus)。

Increase k by 1. 将k增加1。

Here "value" is just a reference received. 这里的“价值”只是收到的参考。 And they are setting it as a property to array directly. 他们将它设置为直接排列的属性。 That means all the filled arrays are just reference to a single array object. 这意味着所有填充的数组只是对单个数组对象的引用。

As you can notice using array.fill you're filling the array with a reference to the same array, 正如您可以注意到使用array.fill,您将使用对同一数组的引用填充数组,

if you want to instantiate each array index to an empty array a normal while loop will do: 如果要将每个数组索引实例化为空数组,则正常的while循环将执行:

 var arr = []; var n = 5 while(n--) arr[n] = [] arr[2].push("third rank item"); console.log(arr); 

Option 2: 选项2:
if you have lodash package available, you can also use _.map as this is specificaly designed to loop through a sparse array (native map will skip non init values) 如果你有lodash包可用,你也可以使用_.map,因为这是专门设计来循环稀疏数组(本机映射将跳过非init值)

 var arr =_.map(new Array(5), (x => [])) arr[2].push("third rank item"); console.log(arr) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script> 

It's happens cause of reference. 这是引用的原因。 Array is a type of object and object works on their references when you fill your array with [] or new Array() fill run only ones and put the same array in all indexes that's why when you update an sub-array all are updated. 数组是一种对象,当你用[] or new Array()填充你的数组时,对象就会对它们的引用起作用,并且在所有索引中放入相同的数组,这就是更新子数组时更新所有索引的原因。

Solution: 解:

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

OR 要么

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

Result: as expected only 2 index of arr is updated. 结果:正如预期的那样,只更新了2个arr索引。

You can try this, 你可以试试这个,

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

Try this ,this is quick solution for you in one line. 试试这个,这是一个快速的解决方案。

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

With ES6 I recommend this method to create 2 or multidimensional arrays: 使用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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM