如何创建包含 1...N 的数组

2022-08-29 21:56:27

我正在寻找以下替代方法,以创建包含1到N的JavaScript数组,其中N仅在运行时已知。

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

对我来说,感觉应该有一种方法可以在没有循环的情况下做到这一点。


答案 1

在 ES6 中使用 Array from()keys() 方法。

Array.from(Array(10).keys())
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

使用点差运算符的较短版本。

[...Array(10).keys()]
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

从 1 开始,将 map 函数传递给 Array from(),并带有一个属性的对象:length

Array.from({length: 10}, (_, i) => i + 1)
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

答案 2

您可以这样做:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

或使用随机值:

Array.apply(null, {length: N}).map(Function.call, Math.random)

结果: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765, 0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915958732, 0.16363654541783035]

解释

首先,请注意,它等效于 ,它只是返回 。我们稍后将使用这一事实。Number.call(undefined, N)Number(N)N

Array.apply(null, [undefined, undefined, undefined])等价于 ,它产生一个三元素数组并分配给每个元素。Array(undefined, undefined, undefined)undefined

如何将其推广到 N 个元素?考虑一下 Array() 是如何工作的,它是这样的:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [ … ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

从 ECMAScript 5 开始,它还接受鸭子类型的类似数组的对象作为其第二个参数。如果我们调用 ,那么它将执行Function.prototype.apply(thisArg, argsArray)Array.apply(null, { length: N })

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

现在我们有一个 N 元素数组,每个元素都设置为 。当我们在其上调用 .map(回调,thisArg)时,每个元素都将设置为 的结果。因此,会将每个元素映射到 ,这与 相同,正如我们之前观察到的,其计算结果为 。这样就完成了其元素与其索引相同的数组。undefinedcallback.call(thisArg, element, index, array)[undefined, undefined, …, undefined].map(Number.call, Number)(Number.call).call(Number, undefined, index, array)Number.call(undefined, index, array)index

为什么要经历麻烦,而不仅仅是?毕竟,这两个表达式都会生成一个未定义元素的 N 元素数组。不同之处在于,在前一个表达式中,每个元素都显式设置为未定义,而在后者中,每个元素从未设置过。根据 .map() 的文档Array.apply(null, {length: N})Array(N)

callback仅对具有赋值的数组索引调用;不会对已删除或从未分配值的索引调用它。

因此,是不够的; 将导致长度为 N 的未初始化数组。Array(N)Array(N).map(Number.call, Number)

兼容性

由于此技术依赖于 ECMAScript 5 中指定的行为,因此在 ECMAScript 5 之前的浏览器中(如 Chrome 14 和 Internet Explorer 9)中不起作用Function.prototype.apply()