如何使用for in循环动态填充数组

4
为返回一个由1到500之间的随机数序列组成的数组set,我尝试重构了一个标准的for循环for(var i = 0; i< 50; i++)并且它起作用了,但是当我使用for in循环进行重构时,它就不行了。我的猜测是在使用array.length属性时出了问题。 TL;DR为什么这会返回一个由50个未定义元素组成的数组,而不是50个随机整数的数组?有没有办法使这种方法起作用?
var set = [];
set.length = 50;

for(var i in set){
    set[i] = Math.floor((Math.random() * 500) + 1);
}

console.log(set);

类似问题:有帮助,但不完全符合我的需求

更新

正如我所怀疑的那样,我错过的一点是设置set.length并不会向数组添加元素,它只会创建一个稀疏数组(一个存在空缺的数组)。在我的情况下,你不能使用for in,因为数组中没有任何可迭代的东西。我要么必须用虚拟内容(即空字符串)填充数组,要么更合理地将我尝试使用.length属性实现的范围部分分离成单独的range变量。

工作版本

var set = [], range = 50;

for(var i = 0; i < range; i++){
    set[i]=Math.floor((Math.random() * 500) + 1);
}

console.log(set);

你不能用那种方式增加数组的大小。 - Daniel A. White
7个回答

5

它返回undefined是因为你使用了set.length设置数组长度。当这个被调用时,数组的所有元素都是undefined

我会完全删除set.length这行代码。

更新后的代码:

var set = [];
for (i = 0; i <= 50; i++) {
  set.push(Math.floor(Math.random() * 500))
}

console.log(set)
=> [138, 215, 149, 180, 348, 497, 88, 156, 238, 439, 130, 185, 20, 116, 330, 131, 188, 257,
    260, 1, 469, 482, 208, 494, 26, 374, 281, 403, 403, 137, 156, 243, 378, 281, 329,
    84, 471, 429, 120, 381, 456, 471, 36, 395, 299, 497, 151, 210, 80, 310]

从技术上讲,“数组的所有元素都是undefined”这种说法并不正确:事实上,可以通过使用Object.getOwnPropertyNames(set)来确定该数组没有任何元素。请参见我的答案 - Brian McCutchon

5

我理解您想要创建一个大小固定但内容动态的数组。如果是这种情况,您需要先创建适当大小的数组。这将为您创建数组。然而,您可以像下面这样自动填充所需的随机值:

var N = 50;
var set = Array.apply(null, {length: N}).map(Function.call, Math.random);

一旦数组自动填充完成,您的其余代码应该按预期工作,只需使用数组中随机数的值即可:

for(var i in set){
    set[i] = Math.floor(set[i] * 500) + 1;
}
console.log(set);
// OUTPUT
// [267, 219, 293, 298, 403, 70, 162, 270, 434, 292, 433, 478, 476, 
//  311, 268, 266, 105, 242, 255, 250, 206, 104, 142, 406, 50, 139, 
//  364, 375, 47, 480, 445, 149, 91, 228, 404, 267, 298, 158, 305, 
//  311, 92, 377, 490, 65, 149, 431, 28, 452, 353, 494]

这是我找到的来源:创建一个包含1...N的JavaScript数组


你的链接是我找到当前困境答案的地方(Niko Ruotsalainen使用spread发布的帖子)。谢谢! - Keith DC

2
问题不在于array.length属性,而是这种扩大数组的方法不会创建“属性”。请注意以下内容:
> [ /*hole*/ , /*hole*/ ,] // An array with two "holes"
[ ,  ]
> new Array(2) // Another way to create an array with two holes
[ ,  ]
> [ undefined, undefined ] // An array with two undefined elements -- not the same
[ undefined, undefined ]
> Object.getOwnPropertyNames([undefined, undefined]);
[ '0', '1', 'length' ]
> Object.getOwnPropertyNames([,,]);
[ 'length' ] // Doesn't have any integer properties!

你所做的是创建一个零元素数组,然后扩展它以包含50个“空洞”,就像有两个空洞的数组一样。由于这个数组没有可枚举属性(length不可枚举),你不能使用for...in迭代它。最终,你最好使用传统的for循环。

编辑

我能够想到的“空洞”的最佳定义是:一个不存在的数组属性,其名称是整数i,满足0 <= i && i < array.length(在考虑这一点时,重要的是要注意JavaScript数组只是具有数字属性(称为“索引”)和一些额外特殊功能的对象。)

有两种方式可以返回未定义的属性引用:要么该属性不存在,要么该属性存在但包含值未定义。因此:

> myObject = { myProp: 1, otherProp: undefined }
{ myProp: 1, otherProp: undefined }
> myObject.nonExistentProperty
undefined
> myObject.otherProp
undefined

现在,未定义属性就像上面的 myObject.nonExistentProperty 一样不存在,所以尝试访问它将导致返回 undefined


未定义与空缺有何不同,为什么在我的示例中访问 set[2] 时返回未定义? - jeanpier_re
@jeanpier_re 请看我的编辑。简而言之,set[2]返回未定义,因为set没有2这个属性。 - Brian McCutchon

2

for in 在这里似乎不是你想要的。尝试使用 for 循环:

var set = [], 
    i = 0, 
    l = null;

set.length = 50;

for(; l = set.length; i < l; i++){
    set[i] = Math.floor((Math.random() * 500) + 1);
}

console.log(set);

1
第二个链接似乎有你需要的答案。 for (var item in array) 循环遍历数组中的每一项,将其存储在“item”中,让您可以迭代每一项。设置数组长度并不会为您提供任何数组项,因此 for in 不执行任何操作 - 没有要迭代的内容。

0

用最简单的方式填充数组的最佳方法是通过实例化 Array() 类,然后使用 Array.prototype.fill() 方法来赋值。

const array_filler = new Array(10).fill(20)

有关更多信息,请阅读以下文章


0
老问题,但因为我在寻找一个简便的方法来做这个,最终我想出了这种方法:
[...Array(50)].map(e => Math.floor((Math.random() * 500) + 1))

如果你想从1到50生成一个数字列表,你可以使用map的第二个参数:

[...Array(50)].map((e, i) => i + 1)

最后,如果你已经有一个返回值的函数,你可以直接调用它:
[...Array(50)].map(Math.random)

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