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

var foo = [];

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

对我来说,我觉得应该有一种不用循环的方法。


当前回答

在ES6中:

Array.from({length: 1000}, (_, i) => i).slice(1);

或者更好(没有额外的变量_,也没有额外的切片调用):

Array.from({length:1000}, Number.call, i => i + 1)

或者,如果您的列表少于256个结果,您可以使用Uint8Array来获得稍快的结果(或者,您可以根据列表的长度使用其他Uint列表,例如Uint16的最大值为65535,或Uint32的最大值4294967295等。不过,正式地说,这些类型的数组只是在ES6中添加的)。例如:

Uint8Array.from({length:10}, Number.call, i => i + 1)

ES5:

Array.apply(0, {length: 1000}).map(function(){return arguments[1]+1});

或者,在ES5中,对于map函数(类似于上面ES6中Array.from函数的第二个参数),可以使用Number.call

Array.apply(0,{length:1000}).map(Number.call,Number).slice(1)

或者,如果你在这里也反对.sslice,你可以执行上面的ES5等效操作(来自ES6),比如:

Array.apply(0,{length:1000}).map(Number.call, Function("i","return i+1"))

其他回答

使用ES6

const generateArray = n => [...Array(n)].map((_, index) => index + 1);

表演

今天2020.12.11我在Chrome v87、Safari v13.1.2和Firefox v83上对macOS HighSierra 10.13.6进行了测试,以确定所选的解决方案。

后果

适用于所有浏览器

解决方案O(基于while)是最快的(除了Firefox for big N-但在那里很快)解决方案T在Firefox上最快解M,P对于小N很快溶液V(lodash)对于大N是快速的对于小N,溶液W、X是缓慢的溶液F缓慢

细节

我执行两个测试用例:

对于小N=10-您可以在这里运行对于大N=1000000,您可以在此处运行

下面的片段展示了所有测试的解决方案ABCDEFGH我JKLMNOPQRSTU五、W十、

函数A(N){return Array.from({length:N},(_,i)=>i+1)}函数B(N){return Array(N).fill().map((_,i)=>i+1);}函数C(N){return Array(N).jjoin().split(',').map((_,i)=>i+1);}函数D(N){return Array.from(数组(N),(_,i)=>i+1)}函数E(N){return Array.from({length:N},(_,i)=>i+1)}函数F(N){return Array.from({length:N},Number.call,i=>i+1)}函数G(N){return(数组(N)+“”).split(',').map((_,i)=>i+1)}函数H(N){return[…Array(N).keys()].map(i=>i+1);}函数I(N){return[…Array(N).keys()].map(x=>x+1);}函数J(N){return[…数组(N+1).keys()].sslice(1)}函数K(N){return[…Array(N).keys()].map(x=>++x);}函数L(N){let arr;(arr=[…数组(N+1).keys()]).shift();返回arr;}函数M(N){var arr=[];变量i=0;而(N-)arr.push(++i);返回arr;}函数N(N){变量a=[],b=N;而(b-)a[b]=b+1;返回a;}函数O(N){var a=阵列(N),b=0;而(b<N)a[b++]=b;返回a;}函数P(N){var foo=[];对于(var i=1;i<=N;i++)foo.push(i);返回foo;}函数Q(N){对于(var a=[],b=N;b-;a[b]=b+1);返回a;}函数R(N){对于(变量i,a=[i=0];i<N;a[i++]=i);返回a;}函数S(N){设foo,x;对于(foo=[x=N];x;foo[x-1]=x--);返回foo;}函数T(N){返回新的Uint8Array(N).map((item,i)=>i+1);}函数U(N){返回“_”。重复(5)。拆分(“”)。映射((_,i)=>i+1);}函数V(N){返回范围(1,N+1);}函数W(N){return[…(函数*(){让i=0;while(i<N)yield++i})()]}函数X(N){函数序列(最大值,步长=1){返回{[Symbol.iiterat]:函数*(){对于(设i=1;i<=max;i+=步长),得出i}}}返回[…序列(N)];}[A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X]。对于每个(F=>{console.log(`${f.name}${f(5)}`);})<script src=“https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js“integrity=”sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==“crossrorigin=”匿名“></script>此代码段仅显示性能测试中使用的函数-它本身不执行测试!

下面是铬的示例结果

以下是摘要(在控制台中运行):

// setup:
var n = 10000000;
function* rangeIter(a, b) {
    for (let i = a; i <= b; ++i) yield i;
}
function range(n) { 
    let a = []
    for (; n--; a[n] = n);
    return a;
}
function sequence(max, step = 1) {
    return {
        [Symbol.iterator]: function* () {
            for (let i = 1; i <= max; i += step) yield i
        }
    }
}

var t0, t1, arr;
// tests
t0 = performance.now();
arr = Array.from({ length: n }, (a, i) => 1)
t1 = performance.now();
console.log("Array.from({ length: n }, (a, i) => 1) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = range(n);
t1 = performance.now();
console.log("range(n) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = Array.from(rangeIter(0, n));
t1 = performance.now();
console.log("Array.from(rangeIter(0, n)) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = [...rangeIter(0, n)];
t1 = performance.now();
console.log("[...rangeIter(0, n)] Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = Array.from(sequence(n));
t1 = performance.now();
console.log("Array.from(sequence(n)) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = [...sequence(n)];
t1 = performance.now();
console.log("[...sequence(n)] Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = Array(n).fill(0).map(Number.call, Number);
t1 = performance.now();
console.log("Array(n).fill(0).map(Number.call, Number) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = Array.from(Array(n).keys());
t1 = performance.now();
console.log("Array.from(Array(n).keys()) Took " + (t1 - t0) + " milliseconds.");

t0 = performance.now();
arr = [...Array(n).keys()];
t1 = performance.now();
console.log("[...Array(n).keys()] Took " + (t1 - t0) + " milliseconds.");

最快的是Array(n).fill(0).map(Number.call,Number),第二个是[…Array(n).keys()]

但是。。。rangeIter的方式非常方便(可以内联),速度快,功能更强大

你可以这样做:

var arr=数组.from(数组(10).keys())arr.shift()控制台日志(arr)

//不分配N大小数组(ES6,带有一些流注释)的解决方案:函数*zeroToN(N/*:数字*/)/*:生成器<number,void,empty>*/{对于(设n=0;n<=n;n+=1),得到n;}//通过这一代,您可以拥有您的阵列console.log([…zeroToN(10-1)])//但是让我们定义一个助手迭代器函数函数mapIterator(迭代器,映射){常量arr=[];for(let result=iterater.next()!result.done;result=iterator.next()){arr.push(映射(result.value));}返回arr;}//现在您有了一个map函数,不需要分配0…N-1数组console.log(mapIterator(zeroToN(10-1),n=>n*n));