79

这是在 JS 中生成 3 个随机数数组的一种有点浪费且不切实际的方法:

[1, 1, 1].map(Math.random) // Outputs: [0.63244645928, 0.59692098067, 0.73627558014]

使用虚拟数组(例如[1, 1, 1]),只是为了让人们可以调用map它,对于足够大的n来说,既浪费(内存)又不切实际。

一个人想要什么,就像一个假设:

repeat(3, Math.random) // Outputs: [0.214259553965, 0.002260502324, 0.452618881464]

我们可以使用 vanilla JavaScript 做的最接近的事情是什么?

我知道像 Underscore 这样的库,但我试图避免这里的库。

我查看了多次重复字符串的答案,但它通常不适用。例如:

Array(3).map(Math.random) // Outputs: [undefined, undefined, undefined]
Array(4).join(Math.random()) // Outputs a concatenation of a repeated number
Array(3).fill(Math.random()) // Fills with the same number

其他几个答案建议修改内置类;我认为完全不能接受的做法。

4

7 回答 7

130

可以使用完成Array.prototype.map,但数组不能为空。先填写

console.log(
    Array(3).fill().map(Math.random)
);

解释:

构造new Array(3)函数创建一个稀疏数组(或“holey”数组,V8 团队称它们为) ,其中包含三个孔,长度为 3。这意味着它等同于[,,,], 创建[<empty>, <empty>, <empty>,](注意 JavaScript 的尾随逗号)。请注意,空槽(即孔)与undefined分配的值不同。undefined是一个实际值,而<empty>只是数组中的一个间隙。

Array.prototype.map对数组中的每个元素调用一次。但是,因为空数组没有赋值,所以根本不会调用回调。例如,[1,,2].map(v=>v*2)会给[2,,4]; 中间的插槽被跳过,因为它在那里有一个间隙。

Enter Array.prototype.fill(value, start?, end?):只有一个参数,它用指定的值填充数组中的每个槽。从技术上讲,第一个参数不是可选的,但是通过省略它,它undefined被用作值。这没关系,因为无论如何都没有使用该值。这种方式Array(3).fill()给了我们[undefined, undefined, undefined]

现在数组中有值,它可以被映射,如上所示。


您也可以在映射之前将值spreadarray入:undefined

console.log(
    [...Array(3)].map(Math.random)
);

解释:

ECMAScript2015 或更新版本中引入的数组运算符将数组中的孔视为undefinedArray.prototype.map在 ES5 中引入(即 ES2015 之前的 IE ),令人困惑的是,数组中的漏洞将被跳过,从而在 JS Array 函数中产生一些不一致,具体取决于它们发布的 ECMAScript 版本。

扩展运算符... 是在 ES2015 中引入的,因此根据规范,它将给定数组中的任何孔转换为undefined. 换句话说,[...Array(3)]给了我们[undefined, undefined, undefined],就像Array(3).fill()上面那样。


有时您可能需要按顺序播种。正如Kevin Danikowski所指出的Array.prototype.map,开箱即用,因为第二个参数是当前键:

const Fibonacci = n => Math.round(((5**.5 + 1) / 2)**n / 5**.5);

console.log(
    Array(10).fill().map((_, i) => Fibonacci(++i))
);

于 2017-02-17T19:42:39.903 回答
40

Underscore.js 有一个times函数,可以完全满足你的要求:

_.times(3, Math.random)

如果您不想使用下划线,您可以编写自己的times函数(从下划线源复制并稍微简化):

times = function(n, iterator) {
  var accum = Array(Math.max(0, n));
  for (var i = 0; i < n; i++) accum[i] = iterator.call();
  return accum;
};
于 2013-08-28T23:37:02.687 回答
24

也许Array.from回调可以使用:

var result = Array.from(Array(3), Math.random);

console.log(result);

与使用 : 相比,这里有一个轻微的优势map:已经需要一个包含所有条目map的数组(可能使用或扩展语法创建),然后从中创建最终数组。因此,一个解决方案总共将创建n个条目两次。不需要带有条目的数组,只需一个具有属性的对象即可,并且正在提供它。fillmapArray.fromlengthArray(3)

所以根据你的喜好,上面也可以这样完成:

var result = Array.from({length:3}, Math.random);

console.log(result);

最后,如果您要为此创建一个repeat函数,您可以命名参数length并使用 ES6 短符号表示对象字面量:

const repeat = (length, cb) => Array.from({length}, cb);

const result = repeat(3, Math.random);
console.log(result);

于 2016-11-07T20:33:56.293 回答
24

最优雅的 ES6:

let times = (n, f) => { while(n-- > 0) f(); }

哦,那不是为了创建一个数组,但它仍然很整洁!

times(3, () => print('wow'))

或红宝石风格:

Object.assign(Number.prototype, { times(f) { x = this; while(x-- > 0) f(); }})
3..times(() => print('wow'))
于 2015-11-07T18:04:02.047 回答
5

创建该repeat功能的现代方法:

repeat = (n, cb) => {[...Array(n)].forEach(cb)}

然后,您可以将其用于:

repeat(3, _ => console.log(Math.random()))

会输出:

0.6324464592887568
0.5969209806782131
0.7362755801487572
于 2018-06-10T10:10:22.687 回答
5

我喜欢这种方式:

[...Array(5).keys()].forEach(index =>
  console.log(`do something ${index}`
)
于 2018-05-14T20:41:11.977 回答
0

您可以执行以下操作:

Iet res = 'n'.repeat(3).split('').map(Math.random)
于 2021-12-09T11:53:41.157 回答