如何在javascript中初始化数组的长度?

How to initialize an array's length in javascript?

我在javascript(包括w3schools和devguru)中阅读过的大多数教程都建议您可以通过使用var test = new Array(4);语法将整数传递给数组构造函数来初始化具有特定长度的数组。

在JS文件中大量使用了这种语法之后,我通过JSlint运行了其中一个文件,它吓坏了:

Error: Problem at line 1 character 22: Expected ')' and instead saw '4'.
var test = new Array(4);
Problem at line 1 character 23: Expected ';' and instead saw ')'.
var test = new Array(4);
Problem at line 1 character 23: Expected an identifier and instead saw ')'.

在阅读了JSlint对其行为的解释之后,JSlint似乎并不真正喜欢new Array()语法,而是在声明数组时更喜欢[]

所以我有几个问题。首先,为什么?我使用new Array()语法是否有风险?是否存在我应该注意的浏览器不兼容问题?第二,如果我切换到方括号语法,有没有任何方法可以声明一个数组并将其长度全部设置在一行上,或者我必须这样做:

1
2
var test = [];
test.length = 4;


  • Array(5)为您提供了一个长度为5但没有值的数组,因此您不能对它进行迭代。

  • Array.apply(null, Array(5)).map(function () {})为您提供了一个长度为5且未定义为值的数组,现在可以对其进行迭代。

  • Array.apply(null, Array(5)).map(function (x, i) { return i; })为您提供了一个长度为5、值为0、1、2、3、4的数组。

  • Array(5).forEach(alert)什么也不做,Array.apply(null, Array(5)).forEach(alert)给你5个提示

  • ES6给了我们Array.from所以现在你也可以使用Array.from(Array(5)).forEach(alert)

  • 如果您想用某个值初始化,这些很好地知道…江户十一〔22〕、江户十一〔23〕。或Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]

  • 小精灵


  • 为什么要初始化长度?理论上没有必要这样做。它甚至可能导致混淆行为,因为所有使用length来查明数组是否为空的测试都将报告数组不是空的。一些测试表明,如果随后填充数组,则设置大型数组的初始长度可能更有效,但不同浏览器的性能增益(如果有)似乎有所不同。

  • JSlint不喜欢new Array(),因为构造者不明确。

    1
    new Array(4);

    创建长度为4的空数组。但是

    1
    new Array('4');

    创建一个包含值'4'的数组。

  • 关于您的注释:在JS中,您不需要初始化数组的长度。它是动态增长的。您可以将长度存储在某个变量中,例如

    1
    2
    3
    4
    5
    6
    var data = [];
    var length = 5; // user defined length

    for(var i = 0; i < length; i++) {
        data.push(createSomeObject());
    }


    使用ES2015 .fill(),您现在可以简单地执行以下操作:

    1
    2
    3
    // `n` is the size you want to initialize your array
    // `0` is what the array will be filled with (can be any other value)
    Array(n).fill(0)

    Array.apply(0, new Array(n)).map(i => value)简洁得多

    可以将.fill()中的0放在.fill()中,在没有参数的情况下运行,这将用undefined填充数组。(但是,这将在typescript中失败)


    最短的:

    1
    [...Array(1000)]


    1
    2
    3
    [...Array(6)].map(x=>0);

    // [0, 0, 0, 0, 0, 0]

    1
    2
    3
    Array(6).fill(0);

    // [0, 0, 0, 0, 0, 0]

    注:不能循环空槽Array(4).forEach( (_,i) => {} )

    1
    2
    3
    Array(6).fill(null).map( (x,i) => i );

    // [0, 1, 2, 3, 4, 5]

    (字体安全)

    创建嵌套数组

    fill创建二维数组时,直观地应该创建新的实例。但实际发生的是,相同的数组将存储为引用。

    1
    2
    3
    4
    5
    var a = Array(3).fill([6]);
    // [[6], [6], [6]]

    a[ 0 ].push( 9 );
    // [[6,9], [6,9], [6,9]]

    解决方案

    1
    2
    3
    4
    var a = [...Array(3)].map(x=>[]);

    a[ 0 ].push( 4, 2 );
    // [[4,2], [ ], [ ]]

    因此,3x2阵列将如下所示:

    1
    2
    3
    4
    5
    [...Array(3)].map(x=>Array(2).fill(0));

    // [ [0,0] ,
    //   [0,0] ,
    //   [0,0] ]


    ES6引入了Array.from,它允许您从任何"类似数组"或iterables对象创建Array

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

    在这种情况下,{length: 10}表示"类似数组"对象的最小定义:仅定义length属性的空对象。

    Array.from允许在生成的数组上映射第二个参数。


    这将把长度属性初始化为4:

    1
    var x = [,,,,];


    我很惊讶没有一个功能性的解决方案建议您将长度设置为一行。以下基于下划线:

    1
    2
    var test = _.map(_.range(4), function () { return undefined; });
    console.log(test.length);

    出于上面提到的原因,我将避免这样做,除非我想将数组初始化为特定的值。值得注意的是,还有其他实现范围的库,包括lo dash和lazy,它们可能具有不同的性能特征。


    (作为评论,这可能更好,但时间太长了)

    所以,在阅读了这篇文章之后,我很好奇预分配是否真的更快,因为理论上它应该更快。然而,这个博客给出了一些建议,反对它http://www.html5rocks.com/en/tutorials/speed/v8/。

    所以还是不确定,我把它放在测试中。事实证明,它似乎更慢。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var time = Date.now();
    var temp = [];
    for(var i=0;i<100000;i++){
        temp[i]=i;
    }
    console.log(Date.now()-time);


    var time = Date.now();
    var temp2 = new Array(100000);
    for(var i=0;i<100000;i++){
        temp2[i] = i;
    }
    console.log(Date.now()-time);

    此代码在几次偶然运行后生成以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ node main.js
    9
    16
    $ node main.js
    8
    14
    $ node main.js
    7
    20
    $ node main.js
    9
    14
    $ node main.js
    9
    19


    1
    2
    3
    var arr=[];
    arr[5]=0;
    alert("length="+arr.length); // gives 6


    请人们不要放弃你的旧习惯。在分配内存一次然后处理该数组中的条目(如旧的)和在数组增长时多次分配内存(这不可避免地是系统在使用其他建议方法的情况下所做的)之间存在很大的速度差异。

    当然,这些都不重要,除非你想用更大的数组做一些酷的事情。就这样。

    由于目前JS中似乎没有设置数组初始容量的选项,所以我使用以下方法…

    1
    2
    3
    4
    5
    6
    7
    var newArrayWithSize = function(size) {
      this.standard = this.standard||[];
      for (var add = size-this.standard.length; add>0; add--) {
       this.standard.push(undefined);// or whatever
      }
      return this.standard.slice(0,size);
    }

    涉及到权衡:

    • 此方法与其他方法一样长时间用于对函数的第一次调用,但很少时间用于以后的调用(除非要求更大的数组)。
    • standard阵列永久性地保留了与您所要求的最大阵列相同的空间。
    • 小精灵

      但是,如果它与你正在做的事情相符合,那就有可能得到回报。非正式时间安排

      1
      for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}

      以相当快的速度(考虑到n=1000000,10000人大约需要50毫秒),并且

      1
      2
      3
      4
      5
      for (var n=10000;n>0;n--) {
        var b = [];for (var add=10000;add>0;add--) {
          b.push(undefined);
        }
      }

      在超过一分钟的时间(在同一个Chrome控制台上,10000个约90秒,或者慢2000倍)。这不仅是分配,还包括10000次推送、for循环等。


      这是另一个解决方案

      1
      2
      3
      var arr = Array.apply( null, { length: 4 } );
      arr;  // [undefined, undefined, undefined, undefined] (in Chrome)
      arr.length; // 4

      apply()的第一个论点是这个对象绑定,我们不关心这个问题,所以我们把它设置为null

      Array.apply(..)调用Array(..)函数,展开{ length: 3 }对象值作为其参数。


      数组构造函数有一个不明确的语法,而jslint终究会伤害您的感情。

      另外,示例代码被破坏,第二条var语句将引发SyntaxError。您正在设置数组test的属性length,因此不需要另一个var

      就你的选择而言,array.length是唯一"干净"的。问题是,为什么首先需要设置大小?尝试重构代码以消除这种依赖关系。


      假设数组的长度是常量。在javascript中,这是我们要做的:

      埃多克斯1〔14〕


      如上所述,使用new Array(size)有点危险。不要直接使用它,而是将它放在"数组创建器函数"中。您可以很容易地确保这个函数没有bug,并且避免直接调用new Array(size)的危险。另外,您可以给它一个可选的默认初始值。这个createArray函数的作用是:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      function createArray(size, defaultVal) {
          var arr = new Array(size);
          if (arguments.length == 2) {
              // optional default value
              for (int i = 0; i < size; ++i) {
                  arr[i] = defaultVal;
              }
          }
          return arr;
      }


      您可以使用array.length = youValue设置阵列长度。

      所以应该是

      1
      2
      var myArray = [];
      myArray.length = yourValue;


      不应使用new Array的原因由以下代码说明:

      1
      2
      3
      4
      5
      var Array = function () {};

      var x = new Array(4);

      alert(x.length);  // undefined...

      其他一些代码可能会干扰数组变量。我知道有人会写这样的代码有点牵强,但是…

      另外,正如FelixKing所说,接口有点不一致,可能导致一些非常难以跟踪的错误。

      如果您想要一个长度为x、填充有未定义的数组(如new Array(x)),您可以这样做:

      1
      2
      3
      4
      5
      var x = 4;
      var myArray = [];
      myArray[x - 1] = undefined;

      alert(myArray.length); // 4