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

Mic*_*ker 470 javascript arrays jslint

我在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;
Run Code Online (Sandbox Code Playgroud)

Rub*_*olk 495

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

  • 这就是我想要的.我想在逻辑序列上应用地图; 这应该做到这一点.谢谢! (8认同)
  • @wdanxna当`Array`被赋予多个参数时,它遍历`arguments`对象并显式地将每个值应用于新数组.当您使用数组或具有长度属性的对象调用`Array.apply`时,`Array`将使用长度来显式设置新数组的每个值.这就是为什么`Array(5)`给出一个包含5个精度的数组,而`Array.apply(null,Array(5))`给出一个5个未定义的数组.有关详细信息,请参阅[this](http://stackoverflow.com/a/20066663/983194)答案. (5认同)
  • `Array.apply(null, Array(5))` 也可以写成 `Array.apply(null, {length: 5})`。确实没有太大区别,但后者明确表示意图是创建一个长度为 5 的数组,而不是一个包含 5 的数组 (4认同)
  • 为什么Array.apply()给它未定义为值? (3认同)
  • Array(5)和新Array(5)有什么区别? (2认同)

Fel*_*ing 367

  1. 为什么要初始化长度?从理论上讲,没有必要这样做.它甚至可能导致令人困惑的行为,因为所有使用它length来查明数组是否为空的测试都会报告该数组不为空.
    一些 测试表明,如果之后填充数组,设置大型数组的初始长度可以更有效,但性能增益(如果有的话)似乎因浏览器而异.

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

    new Array(4);
    
    Run Code Online (Sandbox Code Playgroud)

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

    new Array('4');
    
    Run Code Online (Sandbox Code Playgroud)

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

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

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

for(var i = 0; i < length; i++) {
    data.push(createSomeObject());
}
Run Code Online (Sandbox Code Playgroud)

  • <blockquote>为什么要初始化长度?从理论上讲,没有必要这样做.并且所有使用长度来确定数组是否为空的测试都将失败.</ blockquote>嗯,*性能*也许?设置数组的预先存在的元素比在运行中添加它更快. (130认同)
  • “你为什么要……”在 SO 上被问了很多次。FWIW 我认为当有人发布问题时,假设他们有一个合法的用例并从那里开始是合理的。 (41认同)
  • "放弃旧编程习惯的时间"评论真的没必要.结构合理的语言总是胜过ecmascript mombo jambo (35认同)
  • 数组中的对象数是用户定义的,所以我让用户选择一个数字,然后使用那么多插槽初始化数组.然后我运行一个`for`循环,遍历数组的长度并填充它.我想在JavaScript中还有其他方法可以做到这一点,所以真正的答案是"我为什么要这样做?" 是"因为在用其他语言编程时形成的旧习惯." :) (11认同)
  • @codehead:响应这句话:"设置一个预先存在的数组元素比在运行中添加它更快.":注意`new Array(10)`不会创建一个10的数组未定义的元素.它只是创建一个长度为10的空数组.看到这个令人讨厌的事实的答案:http://stackoverflow.com/questions/18947892/creating-range-in-javascript-strange-syntax (8认同)
  • @mlms只需让for循环迭代用户定义的数字,而不必设置数组长度然后迭代它.这对你更有意义吗? (4认同)
  • 这另一个“答案”只是与发帖者争论,从未真正回答问题。如果您不想初始化数组的长度,请不要在代码中这样做。否则,不要告诉别人他们可以做什么和不能做什么。如果你不能回答这个问题,那就不要回答。 (4认同)
  • @Michael:了解实际用例使我们能够提供更好的解决方案。这被称为 [XY 问题](https://en.wikipedia.org/wiki/XY_problem)。 (3认同)
  • Re:*为什么要初始化长度?从理论上讲,没有必要这样做.* - fwiw,有[这个](http://stackoverflow.com/a/1877479/1028230):`Array(11).join("a")`似乎难以制作JSLint很开心.虽然,正如Milimetric所暗示的那样,[看起来你只需要将数组的长度设置为"n"来欺骗构造函数](http://stackoverflow.com/a/18949651/1028230) - `arr = []; arr.length = N + 1; STR = arr.join(repeatMe);`.哎呀.代码味道. (2认同)
  • 如果我想非顺序地填充数组......或者有双数组(或需要对现有对象进行操作的其他项目)怎么办? (2认同)
  • @FelixKling “为什么”永远不应该成为答案的一部分,但可以是评论。初始化数组的一个很好的理由是您希望映射它来填充它,以避免命令式代码。 (2认同)

AP.*_*AP. 226

使用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)
Run Code Online (Sandbox Code Playgroud)

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

可以0放入in .fill()并运行不带参数,这将填充数组undefined.(但是,这将在Typescript中失败)

  • @Pacerier 我不认为 0 是多余的。根据es6类型定义,这是函数签名:fill(value: T, start?: number, end?: number): this; 因此填充值似乎不是可选的。Typescript 编译将失败,因为函数调用是在上面写的。 (5认同)
  • 是的,请在评论前先试试 (4认同)
  • @GarretWilson 和 @Christian 它是 [__in the spec__](https://www.ecma-international.org/ecma-262/6.0/#sec-array-objects)。_`当 Array 作为函数而不是构造函数被调用时,它还会创建并初始化一个新的 Array 对象。因此函数调用 Array(…) 等价于具有相同参数的对象创建表达式 new Array(…)`_ (2认同)

Vla*_*lad 69

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

// [0, 0, 0, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)

要么

Array(6).fill(0);

// [0, 0, 0, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)

要么

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

// [0, 1, 2, 3, 4, 5]
Run Code Online (Sandbox Code Playgroud)

(打字稿安全)


创建嵌套数组

在创建2D数组时,Array(4).forEach( (_,i) => {} )应直观地创建新实例.但实际发生的事情是将相同的数组存储为参考.

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

a[ 0 ].push( 9 );
// [[6,9], [6,9], [6,9]]
Run Code Online (Sandbox Code Playgroud)

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

a[ 0 ].push( 4, 2 );
// [[4,2], [ ], [ ]]
Run Code Online (Sandbox Code Playgroud)

所以3x2阵列看起来像这样:

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

// [ [0,0] ,
//   [0,0] ,
//   [0,0] ]
Run Code Online (Sandbox Code Playgroud)

  • `a[0].push(9);` `// [ [6, 9], [6], [6] ]` 应该是 `a[0].push(9);` `// [ [ 6, 9], [6, 9], [6, 9] ]` 因为每个嵌套数组都存储为引用,所以改变一个数组会影响其余数组。不过我想你可能只是打错了:) (2认同)
  • `Array(Infinity).fill(0)` 创建你的宇宙!`Array(Infinity).fill(Infinity)` 你是上帝! (2认同)

Mic*_*iti 63

最短的:

[...Array(1000)]
Run Code Online (Sandbox Code Playgroud)

  • Upvoted,但有一点需要注意,你绝对不应该在JS中使用`[`而不使用`;`来启动一行,因为它会尝试取消引用上面的行.因此,在代码的任何部分中可预测地使用此行的安全方法是:`; [... Array(1000)] //.whateverOpsNeeded()` (8认同)
  • @AP这个例子正是许多样式指南要求用分号结束每个语句的原因.在这种情况下,`const a ='a'`将是一个Lint错误.无论如何,这与这个答案无关. (7认同)
  • 这是真的,但在这种情况下,我会说问题是在其他地方,分号和linting现在很重要. (6认同)
  • 尝试在多行js文件中使用它。如果您的第一行是`const a ='a'`,下一行是[[... Array(5)] .// irrelevent`。您认为第一行会解决什么?它将是const a ='a'[... Array(5)]`,这将导致:`Uncaught SyntaxError:Unexpected token ...` (2认同)

Ale*_*tau 35

ES6介绍了Array.from它允许您Array从任何"类似数组"可迭代对象创建:

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

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

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

  • @dain我认为[...数组(10)]更好/sf/answers/3355052571/ (2认同)
  • 为什么更好?不鼓励使用 Array 构造函数,一些 linter 也可能会抱怨 (2认同)

Has*_*war 26

最简单的形式是使用

Array.from({ length: 3 });

// gives you
[undefined, undefined, undefined]
Run Code Online (Sandbox Code Playgroud)

与此不同的是Array(3),它会给你一个无法迭代的数组。Array.from({ length })给你一个可以轻松迭代的数组。

Array.from({ length: 3 }).map((e, idx) => `hi ${idx}`);
// ['hi 1', 'hi 2', 'hi 3']
Run Code Online (Sandbox Code Playgroud)


Šim*_*das 25

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

var x = [,,,,];
Run Code Online (Sandbox Code Playgroud)

  • 想象一下,当性能真的重要时,300件物品! (10认同)
  • 在预分配具有如此小尺寸的阵列时,可能没有太大的性能提升.在创建更大的阵列时,可以更好地感知性能差异.在这些情况下,用逗号初始化它们会有点压倒性. (8认同)
  • 我认为这会在不同的浏览器中产生不同的结果,因为最终的逗号,有时是4,有时是5,请参阅http://stackoverflow.com/questions/7246618/trailing-commas-in-javascript (5认同)
  • 这很聪明.它没有构造函数的灵活性,因为你不能使用变量来设置长度,但它确实回答了我最初的措辞,所以+1. (3认同)
  • 怎么样`var size = 42; var myArray = eval("["+",".repeat(size)+"]");` ? (没那么严重;) (2认同)

chr*_*ang 15

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

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

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

  • 这里确实不需要下划线黑魔法。依赖性就像糖,一开始看起来很甜,但不知不觉中你就得了糖尿病。 (3认同)

j03*_*03m 8

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

因此,在阅读本文之后,我很好奇预分配实际上是否更快,因为理论上它应该是.但是,这篇博客提供了一些建议,提供反对意见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); 
Run Code Online (Sandbox Code Playgroud)

经过几次临时运行后,此代码产生以下结果:

$ 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
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,这看起来很意外,所以我做了[JSPerf测试](http://jsperf.com/allocating-array-size).Chrome结果与您的节点测试相匹配,但是当您为阵列预先分配空间时,Firefox和IE会稍微快一些. (3认同)

use*_*305 8

var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6
Run Code Online (Sandbox Code Playgroud)

  • 是的,但是console.log(arr)给出```[5:0]```这是一个稀疏数组,可能不是想要的. (2认同)

wil*_*ils 8

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

当然,除非你想用更大的数组做一些很酷的事情,否则这一切都不重要.然后呢.

看来目前在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);
}
Run Code Online (Sandbox Code Playgroud)

需要权衡:

  • 对于第一次调用函数,此方法需要与其他函数一样长,但是稍后调用的时间非常短(除非要求更大的数组).
  • standard阵列并永久保留尽可能多的空间,你问了最大的数组.

但如果它符合你正在做的事情那么可能会有回报.非正式时机提出

for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}
Run Code Online (Sandbox Code Playgroud)

以相当快的速度(10000左右,大约50毫秒,n = 1000000大约需要5秒),和

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

超过一分钟(同一镀铬控制台上的10000秒约为90秒,或慢约2000倍).这不仅仅是分配,而且还有10000次推送,for循环等.


zan*_*ngw 7

这是另一种解决方案

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

第一个参数apply()是一个这个对象绑定,我们在这里并不关心,所以我们将它设置为null.

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


Dom*_*omi 5

新版本 (2021)

在现代 JS 引擎中,完全支持稀疏数组。您可以使用[]new Array(len)以任何您喜欢的方式,即使是随机访问。字典模式似乎已成为过去。

在当前的 Chrome(我猜是任何 V8 环境)中,数组的长度可以达到 2^32-1,并且分配是稀疏的(意味着空块不会占用任何内存):

在此处输入图片说明

在此处输入图片说明

旧版本(过时)

如上所述,使用new Array(size)有点危险。不要直接使用它,而是将它放在“数组创建者函数”中。您可以轻松确保此函数没有错误,并避免new Array(size)直接调用的危险。此外,您可以给它一个可选的默认初始值。这个createArray函数正是这样做的:

function createArray(size, defaultVal) {
    const arr = new Array(size);
    if (defaultVal !== undefined) {
        // optional default value
        for (let i = 0; i < size; ++i) {
            arr[i] = defaultVal;
        }
    }
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

  • 你也可以只调用不带参数的`.fill`,然后你可以迭代数组:`new Array(10).fill().forEach(i =&gt; console.log(i))` (3认同)
  • 6 年后......无论如何,当你写这篇文章时,你可能认为你使用的是不同的语言,因为你实际上并没有使用 int 在 JavaScript 中定义整数(使用 `let`、`var` 或 `const` )。我只是想为下一个复制 StackOverflow 代码并意识到它不起作用的人澄清一切 (2认同)
  • @sno2 那里肯定有错字。有趣的是,从那时起很多事情都发生了变化,所以我更新了整个事情 (2认同)