如何创建一个包含1…N的数组。

21 浏览
0 Comments

如何创建一个包含1…N的数组。

我正在寻找创建JavaScript数组的任何替代方案,该数组包含从1到N的数字,其中N仅在运行时知道。

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

对我来说,感觉应该有一种不需要循环就可以做到这一点的方法。

admin 更改状态以发布 2023年5月23日
0
0 Comments

你可以这样做:

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个元素的数组,每个元素都设置为undefined。当我们在其上调用.map(callback, thisArg)时,每个元素将被设置为callback.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。这完成了一个元素与其索引相同的数组。

为什么要使用Array.apply(null, {length: N}),而不是直接使用Array(N)?毕竟,这两个表达式都会得到N个未定义元素的数组。区别在于,在前一种表达式中,每个元素都被明确设置为未定义,而在后一种表达式中,每个元素都没有被设置。根据.map()的文档:

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

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

兼容性

由于这种技术依赖于在ECMAScript 5中指定的Function.prototype.apply()的行为,因此在先ECMAScript 5的浏览器中(如Chrome 14和Internet Explorer 9)将无法工作

0
0 Comments

在ES6中使用数组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]

通过将map函数传递给带有length属性的对象的数组from()方法,从1开始:

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

0