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

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

在我的js文件中广泛使用此语法后,我通过jsLint运行了其中一个文件,结果很糟糕

错误:第1行第22个字符的问题:预期为')',而是显示为'4'。
var test = new Array(4);
第1行第23个字元的问题:预期为';' 而是看到')'。
var test = new Array(4);
第1行第23个字符处的问题:需要标识符,而看到了')'。

阅读完jsLint对其行为的解释之后,看起来jsLint并不真正喜欢new Array()语法,而是[]在声明数组时更喜欢

所以我有几个问题:

首先,为什么?我使用new Array()语法代替会冒任何风险吗?我应该注意浏览器的不兼容性吗?

其次,如果我切换到方括号语法,是否有任何方法可以声明一个数组并将其长度全部设置在一行上,或者我必须执行以下操作:

var test = [];
test.length = 4;
Davaid阳光2020/03/12 16:57:48

As explained above, using new Array(size) is somewhat dangerous. Instead of using it directly, place it inside an "array creator function". You can easily make sure that this function is bug-free and you avoid the danger of calling new Array(size) directly. Also, you can give it an optional default initial value. This createArray function does exactly that:

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;
}
猿Sam2020/03/12 16:57:48

You can set the array length by using array.length = youValue

So it would be

var myArray = [];
myArray.length = yourValue;
樱十三2020/03/12 16:57:48

这是另一种解决方案

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

的第一个参数apply()是this对象绑定,此处我们不在乎,因此将其设置为null

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

Tony宝儿2020/03/12 16:57:48

令我惊讶的是,还没有一个功能性的解决方案可以让您在一行中设置长度。以下基于UnderscoreJS:

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

由于上述原因,除非我想将数组初始化为特定值,否则我将避免这样做。有趣的是,还有其他实现范围的库,包括Lo-dash和Lazy,它们可能具有不同的性能特征。

猴子神无2020/03/12 16:57:48

数组构造函数的语法不明确,毕竟JSLint只会伤害您的感觉。

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

As far as your options go, array.length is the only "clean" one. Question is, why do you need to set the size in the first place? Try to refactor your code to get rid of that dependency.

乐米亚2020/03/12 16:57:48
var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6
樱GO2020/03/12 16:57:48

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

因此,看完这篇文章后,我很好奇预分配实际上是否更快,因为从理论上讲应该如此。但是,此博客提供了一些建议,建议不要使用它http://www.html5rocks.com/en/tutorials/speed/v8/

因此仍然不确定,我将其进行了测试。事实证明,它似乎实际上要慢一些。

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

几次随意运行后,此代码将产生以下内容:

$ 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
樱JimPro2020/03/12 16:57:48

请人们暂时不要放弃您的旧习惯。在分配内存一次然后使用该数组中的条目(如旧),以及随着数组的增长多次分配内存之间,在速度上存在很大差异(这不可避免地是系统采用其他建议的方法在后台进行的操作) 。

当然,这一切都不重要,除非您想对更大的阵列做一些很棒的事情。然后就可以了。

鉴于目前在JS中似乎仍然无法设置数组的初始容量,我使用以下方法...

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阵列确实会永久保留您所需的最大阵列的空间。

但是,如果它适合您的工作,那么可能会有所收获。非正式时机

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

以相当快的速度(对于10000,大约需要50ms,因为n = 1000000大约需要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循环等。

神奇逆天猪猪2020/03/12 16:57:48

最短的:

[...Array(1000)]
Davaid番长2020/03/12 16:57:48

ES6引入了Array.from它,您可以Array从任何“类似数组”iterables对象创建一个

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

在这种情况下,{length: 10}代表了“数组状”对象的最小定义:一个仅length定义属性的空对象

Array.from 允许第二个参数映射到结果数组上。

猴子蛋蛋2020/03/12 16:57:48

这会将length属性初始化为4:

var x = [,,,,];
猴子逆天2020/03/12 16:57:48

借助ES2015,.fill()您现在可以轻松执行以下操作:

// `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)

可以插入0in .fill()并在不使用参数的情况下运行,这将用填充数组undefined但是,这将在Typescript中失败

阿飞小卤蛋2020/03/12 16:57:48
[...Array(6)].map(x=>0);

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

要么

Array(6).fill(0);

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

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


要么

TypeScript安全

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

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

要么

使用函数的经典方法(可在任何浏览器中使用)

function NewArray( size ) { var x=[];for(var i = 0;i<size;++i)x[i]=i;return x; }

var a = NewArray( 10 );
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

创建嵌套数组

直观地创建2D数组时,fill应创建新实例。但是实际上要发生的是同一数组将被存储为参考。

var a = Array(3).fill([6]); 
// [[6], [6], [6]]

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

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

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

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

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

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

N维数组

function NArray( ...dimensions ) {
    var index = 0;
    function NArrayRec( dims ) {
        var first = dims[ 0 ], next = dims.slice().splice( 1 ); 
        if( dims.length > 1 ) 
            return Array( dims[ 0 ] ).fill( null ).map( ( x , i ) => NArrayRec( next ) );
        return Array( dims[ 0 ] ).fill( null ).map( ( x, i ) => ( index++ ) );
    }
    return NArrayRec( dimensions );
}

var arr = NArray( 3,2,4 );
// [   [   [  0, 1, 2, 3 ],[  4, 5, 6, 7 ]   ],
//     [   [  8, 9,10,11 ],[ 12,13,14,15 ]   ],
//     [   [ 16,17,18,19 ],[ 20,21,22,23 ]   ]   ]

初始化棋盘

var Chessboard = [...Array( 8 )].map( (x,j) =>
    Array( 8 ).fill( null ).map( (y,i) =>
        `${ String.fromCharCode( 65 + i ) }${ 8 - j }`));

// [ [ A8,B8,C8,D8,E8,F8,G8,H8 ],
//   [ A7,B7,C7,D7,E7,F7,G7,H7 ],
//   [ A6,B6,C6,D6,E6,F6,G6,H6 ],
//   [ A5,B5,C5,D5,E5,F5,G5,H5 ],
//   [ A4,B4,C4,D4,E4,F4,G4,H4 ],
//   [ A3,B3,C3,D3,E3,F3,G3,H3 ],
//   [ A2,B2,C2,D2,E2,F2,G2,H2 ],
//   [ A1,B1,C1,D1,E1,F1,G1,H1 ] ]