How to create an array containing 1…N

后端 未结 30 1544
旧时难觅i
旧时难觅i 2020-11-22 01:04

I\'m looking for any alternatives to the below for creating a JavaScript array containing 1 through to N where N is only known at runt

30条回答
  •  故里飘歌
    2020-11-22 02:05

    You can do so:

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

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

    or with random values:

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

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

    Explanation

    First, note that Number.call(undefined, N) is equivalent to Number(N), which just returns N. We'll use that fact later.

    Array.apply(null, [undefined, undefined, undefined]) is equivalent to Array(undefined, undefined, undefined), which produces a three-element array and assigns undefined to each element.

    How can you generalize that to N elements? Consider how Array() works, which goes something like this:

    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;
    }
    

    Since ECMAScript 5, Function.prototype.apply(thisArg, argsArray) also accepts a duck-typed array-like object as its second parameter. If we invoke Array.apply(null, { length: N }), then it will execute

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

    Now we have an N-element array, with each element set to undefined. When we call .map(callback, thisArg) on it, each element will be set to the result of callback.call(thisArg, element, index, array). Therefore, [undefined, undefined, …, undefined].map(Number.call, Number) would map each element to (Number.call).call(Number, undefined, index, array), which is the same as Number.call(undefined, index, array), which, as we observed earlier, evaluates to index. That completes the array whose elements are the same as their index.

    Why go through the trouble of Array.apply(null, {length: N}) instead of just Array(N)? After all, both expressions would result an an N-element array of undefined elements. The difference is that in the former expression, each element is explicitly set to undefined, whereas in the latter, each element was never set. According to the documentation of .map():

    callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

    Therefore, Array(N) is insufficient; Array(N).map(Number.call, Number) would result in an uninitialized array of length N.

    Compatibility

    Since this technique relies on behaviour of Function.prototype.apply() specified in ECMAScript 5, it will not work in pre-ECMAScript 5 browsers such as Chrome 14 and Internet Explorer 9.

提交回复
热议问题