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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4852017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:25:42  来源:igfitidea点击:

How to initialize an array's length in JavaScript?

javascriptarraysjslint

提问by Michael Martin-Smucker

Most of the tutorials that I've read on arrays in JavaScript (including w3schoolsand devguru) suggest that you can initialize an array with a certain length by passing an integer to the Array constructor using the var test = new Array(4);syntax.

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

After using this syntax liberally in my js files, I ran one of the files through jsLint, and it freaked out:

在我的 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 ')'.

错误:第 1 行字符 22 出现问题:应为 ')' 而看到的是 '4'。
var test = new Array(4);
第 1 行字符 23 处的问题:应为 ';' 而是看到了')'。
var test = new Array(4);
第 1 行字符 23 出现问题:需要一个标识符,但看到的是“)”。

After reading through jsLint's explanation of its behavior, it looks like jsLint doesn't really like the new Array()syntax, and instead prefers []when declaring arrays.

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

So I have a couple questions:

所以我有几个问题:

First, why? Am I running any risk by using the new Array()syntax instead? Are there browser incompatibilities that I should be aware of?

首先,为什么?我是否会因为使用new Array()语法而冒任何风险?是否存在我应该注意的浏览器不兼容问题?

And second, if I switch to the square bracket syntax, is there any way to declare an array and set its length all on one line, or do I have to do something like this:

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

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

采纳答案by Felix Kling

  1. Why do you want to initialize the length? Theoretically there is no need for this. It can even result in confusing behavior, because all tests that use the lengthto find out whether an array is empty or not will report that the array is not empty.
    Sometestsshow that setting the initial length of large arrays canbe more efficient if the array is filled afterwards, but the performance gain (if any) seem to differ from browser to browser.

  2. jsLint does not like new Array()because the constructer is ambiguous.

    new Array(4);
    

    creates an empty array of length4. But

    new Array('4');
    

    creates an array containing the value'4'.

  1. 为什么要初始化长度?理论上没有这个必要。它甚至会导致令人困惑的行为,因为所有使用length来确定数组是否为空的测试都会报告该数组不为空。
    一些试验表明,设定大的阵列的初始长度可以如果该阵列被充满之后更有效,但性能增益(如果有的话)似乎不同于浏览器的浏览器。

  2. jsLint 不喜欢,new Array()因为构造函数不明确。

    new Array(4);
    

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

    new Array('4');
    

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

Regarding your comment: In JS you don't need to initialize the length of the array. It grows dynamically. You can just store the length in some variable, e.g.

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

var data = [];
var length = 5; // user defined length

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

回答by Ruben Stolk

  • Array(5)gives you an array with length 5 but no values, hence you can't iterate over it.

  • Array.apply(null, Array(5)).map(function () {})gives you an array with length 5 and undefined as values, now it can be iterated over.

  • Array.apply(null, Array(5)).map(function (x, i) { return i; })gives you an array with length 5 and values 0,1,2,3,4.

  • Array(5).forEach(alert)does nothing, Array.apply(null, Array(5)).forEach(alert)gives you 5 alerts

  • ES6gives us Array.fromso now you can also use Array.from(Array(5)).forEach(alert)

  • If you want to initialize with a certain value, these are good to knows...
    Array.from('abcde'), Array.from('x'.repeat(5))
    or Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 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)

  • 如果你想用某个值初始化,这些很好知道...
    Array.from('abcde')Array.from('x'.repeat(5))
    或者Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]

回答by AP.

With ES2015 .fill()you can now simply do:

使用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)

Which is a lot more concise than Array.apply(0, new Array(n)).map(i => value)

哪个比 Array.apply(0, new Array(n)).map(i => value)

It is possible to drop the 0in .fill()and run without arguments, which will fill the array with undefined. (However, this will fail in Typescript)

它能够丢弃0.fill()和不带参数运行,这将填补阵列undefined。(但是,这将在 Typescript 中失败

回答by Vlad

[...Array(6)].map(x => 0);
// [0, 0, 0, 0, 0, 0]

OR

或者

Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]

Note: you can't loop empty slots i.e. Array(4).forEach(() => …)

注意:你不能循环空槽,即 Array(4).forEach(() => …)



OR

或者

( typescript safe)

打字稿安全

Array(6).fill(null).map((_, i) => i);
// [0, 1, 2, 3, 4, 5]


OR

或者

Classic method using a function ( works in any browser )

使用函数的经典方法(适用于任何浏览器)

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]


Creating nested arrays

创建嵌套数组

When creating a 2Darray with the fillintuitively should create new instances. But what actually going to happen is the same array will be stored as a reference.

创建一个当二维数组与fill直觉应该创建新实例。但实际发生的是相同的数组将被存储为引用。

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

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

Solution

解决方案

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

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

So a 3x2 Array will look something like this:

所以一个 3x2 数组看起来像这样:

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


N-dimensional array

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]  ]   ]


Initialize a chessboard

初始化棋盘

var Chessboard = [...Array(8)].map((x, j) => {
    return Array(8).fill(null).map((y, i) => {
        return `${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] ]

回答by Michael Mammoliti

The shortest:

最短的:

[...Array(1000)]

回答by Alexander Shutau

ES6 introduces Array.fromwhich lets you create an Arrayfrom any "array-like"or iterablesobjects:

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

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

In this case {length: 10}represents the minimal definition of an "array-like"object: an empty object with just a lengthproperty defined.

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

Array.fromallows for a second argument to map over the resulting array.

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

回答by ?ime Vidas

This will initialize the length property to 4:

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

var x = [,,,,];

回答by christang

I'm surprised there hasn't been a functional solution suggested that allows you to set the length in one line. The following is based on UnderscoreJS:

我很惊讶没有建议的功能解决方案允许您在一行中设置长度。以下基于 UnderscoreJS:

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

For reasons mentioned above, I'd avoid doing this unless I wanted to initialize the array to a specific value. It's interesting to note there are other libraries that implement range including Lo-dash and Lazy, which may have different performance characteristics.

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

回答by wils

Please people don't give up your old habits just yet. There is a large difference in speed between allocating memory once then working with the entries in that array (as of old), and allocating it many times as an array grows (which is inevitably what the system does under the hood with other suggested methods).

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

None of this matters of course, until you want to do something cool with larger arrays. Then it does.

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

Seeing as there still seems to be no option in JS at the moment to set the initial capacity of an array, I use the following...

鉴于目前 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);
}

There are tradeoffs involved:

涉及到权衡:

  • This method takes as long as the others for the first call to the function, but very little time for later calls (unless asking for a bigger array).
  • The standardarray does permanently reserve as much space as the largest array you have asked for.
  • 这个方法在第一次调用函数时花费的时间与其他方法一样长,但在以后的调用中花费的时间很少(除非要求更大的数组)。
  • standard阵列确实会永久保留与您要求的最大阵列一样多的空间。

But if it fits with what you're doing there can be a payoff. Informal timing puts

但如果它适合你正在做的事情,就会有回报。非正式计时看跌期权

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

at pretty speedy (about 50ms for the 10000 given that with n=1000000 it took about 5 seconds), and

以相当快的速度(对于 10000 大约需要 50 毫秒,因为 n=1000000 需要大约 5 秒),并且

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

at well over a minute (about 90 sec for the 10000 on the same chrome console, or about 2000 times slower). That won't just be the allocation, but also the 10000 pushes, for loop, etc..

超过一分钟(同一 Chrome 控制台上的 10000 大约需要 90 秒,或者慢大约 2000 倍)。这不仅是分配,还有 10000 次推送、for 循环等。

回答by user1067305

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