声明JavaScript数组时,"Array()"和"[]"有什么区别?

961

声明数组的这两种方式之间的真正区别是什么:

var myArray = new Array();

以及

var myArray = [];

2
[] token: ARRAY_INIT; new Array tokens: NEW, IDENTIFIER; new Array() tokens: NEW, IDENTIFIER, CALL - noobninja
20个回答

1069

这两者有所不同,但在这个例子中没有区别。

使用更冗长的方式:new Array() 在参数上有一个额外选项:如果你将一个数字传递给构造函数,那么你会得到一个该长度的数组:

x = new Array(5);
alert(x.length); // 5
为了说明创建数组的不同方法:
var a = [],            // these are the same
    b = new Array(),   // a and b are arrays with length 0

    c = ['foo', 'bar'],           // these are the same
    d = new Array('foo', 'bar'),  // c and d are arrays with 2 strings

    // these are different:
    e = [3]             // e.length == 1, e[0] == 3
    f = new Array(3),   // f.length == 3, f[0] == undefined

;

另一个不同之处在于使用new Array()时,您可以设置数组的大小,这会影响堆栈大小。如果您遇到堆栈溢出(Array.push与Array.unshift的性能比较),这可能很有用,当数组的大小超过堆栈大小时会发生堆栈溢出并且必须重新创建。因此,在某些情况下,使用new Array()实际上可以提高性能,因为您可以防止溢出发生。

正如这个答案所指出的那样,new Array(5)实际上不会向数组添加五个undefined项,而只是为五个项添加空间。请注意,以这种方式使用Array将使依靠array.length进行计算变得困难。


70
这有一点错误。新数组(new Array())和空数组([])之间有一个非常重要的区别,我将在我的回答中详细阐述。 - coderjoe
34
但正如你在回答中所指出的,只有当你完全疯狂并覆盖Array函数时才会不同吗? - nickf
21
使用new操作符的重要性在于,它会导致解释器执行各种额外步骤,以便进入全局作用域,寻找构造函数,调用构造函数并将结果赋值... 在大多数情况下,这将是一个运行时数组。你可以通过只使用[]来避免寻找全局构造函数的开销。这可能看起来微不足道,但当你的应用程序需要接近实时性能时,它可以产生影响。 - coderjoe
5
性能差别非常大:http://jsperf.com/create-an-array-of-initial-size/2 - Marco Luglio
4
没错,但在我加入分号或换行的大多数地方你也不需要它们。这是关于一致性和易读性的。你懂的,在我看来。 - nickf
显示剩余2条评论

813

使用隐式数组和使用数组构造函数创建数组之间的区别微妙但很重要。

当您使用:

var a = [];
你正在告诉解释器创建一个新的运行时数组。完全不需要额外的处理。完成了。
如果你使用:
var a = new Array();
你在告诉编译器:我想调用构造函数 "Array" 并生成一个对象。然后它会通过你的执行上下文查找要调用的构造函数,并调用它,从而创建你的数组。
你可能会认为:"好像这没有任何关系。它们是一样的!"。遗憾的是,你不能保证这一点。
举个例子:
function Array() {
    this.is = 'SPARTA';
}

var a = new Array();
var b = [];

alert(a.is);  // => 'SPARTA'
alert(b.is);  // => undefined
a.push('Woa'); // => TypeError: a.push is not a function
b.push('Woa'); // => 1 (OK)
在上面的示例中,第一次调用将如预期地弹出“SPARTA”。第二次不会。你最终会看到未定义。你还会注意到b包含所有的原生Array对象函数,如push,而另一个则没有。
尽管你可能会期望发生这种情况,但它只是说明了[]new Array()并不相同。
如果您知道您只想要一个数组,则最好只使用[]。我也不建议四处重新定义Array...

185
好的,我知道了。我不知道会有什么样的人会覆盖掉数组类(overwirte the array class)…… - nickf
171
你说得没错,只有疯子才会重写数组类。现在花点时间考虑一下,使用 new Array() 会让解释器为支持这些疯子做更多的工作。我完全避免这种情况,改用 []。 - coderjoe
57
JavaScript 可能导致的全球污染类型的一个很好的例子。 - David Snabel-Caunt
8
值得注意的是,使用新的Array(size)比使用[]符号的其他可能方法更快。来源:http://jsperf.com/create-an-array-of-initial-size/2 - Marco Luglio
10
很遗憾,那个测试没有做好。它测试的是用数组初始化数组并进行数组访问的初始化,没有控制以证明浏览器实际上正在预分配内存(规范并没有要求他们这样做)。如果我们可以假设数组访问是恒定的,并且大部分时间都会在两个示例中花费分配内存,则在实例化数百万个数组时,[] 可能更可取。http://jsperf.com/array-instanciation - coderjoe
显示剩余9条评论

129

还有一个重要的区别,没有任何答案提到过。

来自这个:

new Array(2).length           // 2
new Array(2)[0] === undefined // true
new Array(2)[1] === undefined // true

你可能认为new Array(2)等同于[undefined, undefined],但实际上并不是这样。

我们可以用map()来试一下:

[undefined, undefined].map(e => 1)  // [1, 1]
new Array(2).map(e => 1)            // "(2) [undefined × 2]" in Chrome

你看,这两种语义完全不同!那么为什么呢?

根据ES6规范22.1.1.2,Array(len)的作用只是创建一个新的数组,其属性length设置为参数len,也就是说在这个新创建的数组中没有任何真实元素

map()函数根据规范22.1.3.15首先会检查HasProperty,然后调用回调函数,但事实证明:

new Array(2).hasOwnProperty(0) // false
[undefined, undefined].hasOwnProperty(0) // true

因此,您不能期望任何迭代函数在由new Array(len)创建的数组上正常工作。

顺便说一下,Safari和Firefox对这种情况有更好的“打印”:

// Safari
new Array(2)             // [](2)
new Array(2).map(e => 1) // [](2) 
[undefined, undefined]   // [undefined, undefined] (2) 

// Firefox
new Array(2)             // Array [ <2 empty slots> ]
new Array(2).map(e => 1) // Array [ <2 empty slots> ]
[undefined, undefined]   // Array [ undefined, undefined ]

我已经向Chromium提交了一个问题,并要求他们修复这个令人困惑的打印:https://bugs.chromium.org/p/chromium/issues/detail?id=732021

更新:它已经修复。现在Chrome打印为:

new Array(2)             // (2) [empty × 2]

1
这是有道理的,我只是遇到了一个不同的构造,我找不到文档参考:[...Array(2)] ,它从结果的角度来看等价于 [undefined, undefined] - Roberto Andrade
看起来对我之前评论的答案是“扩展运算符”:https://javascript.info/rest-parameters-spread-operator - Roberto Andrade
@RobertoAndrade 这是有道理的,因为展开运算符需要读取条目,以便可以进行复制...而读取这样的空槽通常会返回undefined - Hux
new Array(2) 的等价应该是 [,,],而不是 [undefined, undefined],对吧? - angleKH

54

有趣的是,在Chrome浏览器中,new Array(size)创建数组的速度几乎比[]快2倍,在FF和IE中则差不多(通过创建和填充数组来衡量)。这只有在您知道数组的大致大小时才会有所影响。如果添加的项比您给定的长度还多,则性能提升就会丢失。

更准确地说:Array()是一个快速的常量时间操作,不需要分配内存,而[]是一种线性时间操作,设置类型和值。


3
我在Node.js中进行了许多测试:当您需要将某些项目放入数组中时,0 <= size <= ~1000时使用new Array(length),而在size > ~1000时则使用[] - glukki
1
请查看此链接:https://dev59.com/uWs05IYBdhLWcg3wNPS7 - Xsmael

44

若需要了解更多信息,请参阅该页面,它解释了为什么您永远不需要使用new Array()

在JavaScript中您永远不需要使用new Object()。直接使用对象字面量{}即可。同样地,不要使用new Array(),可以用数组字面量[]代替。在JavaScript中,数组的工作方式与Java中的数组完全不同,使用类似Java的语法会让您感到困惑。

不要使用new Numbernew Stringnew Boolean。这些形式会产生不必要的对象包装器。只需使用简单的字面量即可。

同时,请查看评论 - new Array(length) 的形式在今天的JavaScript实现中没有任何有用的目的。


3
Crockford建议使用[]代替new Array()。不幸的是,他在链接的文章中没有解释为什么要这样做。我猜想这只是一个空间和速度的问题。http://javascript.crockford.com/code.html - Nosredna
4
Crockford不喜欢在JavaScript中使用“new”关键字来创建对象的新实例。他在讲座中表示,他认为这会产生歧义,并且不适合JavaScript的原型式继承风格。他特别指的是用户创建的对象构造器,但基于这种观点,可以很容易理解为什么在有替代语法时他会建议你不要将其用于内置对象。 - Alana Storm
@Alan Storm:至少对于Number、String和Boolean,他说“这些形式会产生不必要的对象包装器”,但我猜这不适用于Array。 - BarelyFitz

8
第一种是默认对象构造函数调用。如果您想要,可以使用它的参数。
var array = new Array(5); //initialize with default length 5

第二种方法可以让您创建非空数组:
var array = [1, 2, 3]; // this array will contain numbers 1, 2, 3.

1
你可以使用详细构造函数完成同样的事情:var array = new Array(1, 2, 3); - nickf
那么我猜你可以使用方括号做 var array = [5],但不能使用构造函数,因为 var array = Array(5) 会创建一个有5个空元素的空数组。 - cdmckay
3
@BarelyFitz说的就是这个意思。在Bogdans的回答中,他说构造函数调用不能用来初始化数组,但他是错误的。我的评论只是为了澄清,你不能使用构造函数调用来初始化单个元素的数组。 - cdmckay
1
@cdmckay:抱歉,我误解了你的评论。澄清一下:new Array(arg)-如果arg是数字,则创建一个长度为arg的空数组;new Array(arg1,arg2)-创建一个新数组并初始化数组元素。因此,如果您想创建一个只有一个数字元素的数组,例如[5],则不能使用new Array(5)。但实际上,您永远不应该使用new Array(),所以这是一个无意义的观点。 - BarelyFitz
我认为值得注意的是,[1,2,3,4,5] 几乎和 new Array(5) 一样快,而后者只是在准备存储空间... 在 http://jsperf.com/array-instanciation/2 上查看测试用例并阅读测试用例,在抱怨之前请注意,下半部分与上半部分的测试不是在做同样的事情,最后三个测试用例还有值赋值。 - Sampo Sarrala - codidact.org
显示剩余2条评论

8
为了更好地理解[]new Array()
> []
  []
> new Array()
  []
> [] == []
  false
> [] === []
  false
> new Array() == new Array()
  false
> new Array() === new Array()
  false
> typeof ([])
  "object"
> typeof (new Array())
  "object"
> [] === new Array()
  false
> [] == new Array()
  false

上述结果来自于在Windows 7上使用Google Chrome控制台。

4
为什么 [] == [] 或者 [] === [] 是 false? - anu
5
只有当运算符所引用的操作数指向同一对象时,比较对象的表达式才为真。 - srph
1
这个答案挑选了一些例子来暗示这两个结构是相同的。本页面上的其他帖子指出了它们之间的区别,例如Array(3)new Array(3)[3]不同。 - ggorlen

5
我可以从Fredrik的例子开始,更加具体地解释一下。
var test1 = [];
test1.push("value");
test1.push("value2");

var test2 = new Array();
test2.push("value");
test2.push("value2");

alert(test1);
alert(test2);
alert(test1 == test2);
alert(test1.value == test2.value);

我刚刚向数组中添加了另一个值,并进行了四次提醒: 第一次和第二次是为了确保存储在每个数组中的值,它们将返回相同的结果! 现在尝试第三个,它返回false,这是因为JS将test1视为具有数组数据类型的变量,并将test2视为具有数组功能的对象,这里有一些细微的差异。
第一个区别是当我们调用test1时,它会自动调用变量,并返回存储在此变量中的值,而忽略其数据类型!但是,当我们调用test2时,它调用Array()函数,然后将我们“推入”的值存储在其“Value”属性中,当我们提醒test2时,它返回数组对象的“Value”属性。 所以当我们检查test1是否等于test2时,它们永远不会返回true,因为一个是函数,另一个是变量(类型为数组),即使它们具有相同的值!
为了确保这一点,请尝试第4个提醒,其中添加了.value; 它将返回true。 在这种情况下,我们告诉JS:“忽略容器的类型,无论它是函数还是变量,请比较存储在每个容器中的值并告诉我们您看到了什么!” 这正是发生的事情。
我希望我清楚地表达了这一思想,对我的糟糕英语表示抱歉。

19
这个荒谬无比的言论竟然被点赞了,真是不可思议。无论你如何制造这些数组并进行比较,结果都是错误的,因为它们比较的是对象标识符而不是它们的值。数组没有 value 属性。[]new Array() 是相同的;在这两种情况下,.value 都将是 undefined,并且对它们进行比较总是会返回 false。 - slikts
同意,这个答案毫无意义,也没有展示任何东西。array.value根本不存在,而且typeof []typeof new Array()都返回object。这就是为什么有一个名为Array.isArray的函数的原因之一。 - gman
嗯,伙计们,我同意你们的看法 :) 那时候我写了一些完全无意义的东西 :). 现在我已经给同一个问题添加了正确的答案。请告诉我你们的看法。我非常感谢你们的意见。 - Kholio

4

这其中的细节远不止表面看起来的那么简单。大多数其他答案是正确的 但同时..

new Array(n)

  • 允许引擎重新分配空间以容纳 n 个元素
  • 优化了数组创建
  • 创建的数组被标记为稀疏,其具有最低效的数组操作,因为每次索引访问都要检查边界,查看值是否存在并遍历原型链
  • 如果数组被标记为稀疏数组,在V8中就没有回头路了,即使您稍后用内容(紧凑的数组)填充它,它在其生命周期中始终会慢些,无论是1毫秒还是2个小时之后。

[1, 2, 3] || []

  • 创建的数组被标记为紧凑数组(除非您使用delete[1,,3]语法)
  • 优化了数组操作(例如for ..forEachmap等)
  • 随着数组的增长,引擎需要重新分配空间

可能不适用于旧版浏览器/浏览器。


4

当您初始化没有任何长度的数组时并没有任何区别。所以var a = []var b = new Array()是一样的。

但是,如果你像这样初始化长度 var b = new Array(1);,它将设置数组对象的长度为1。因此,它等同于var b = []; b.length=1;

每当你使用array_object.push时,这将会成为问题,它会在最后一个元素之后添加项目并增加长度。

var b = new Array(1);
b.push("hello world");
console.log(b.length); // print 2

vs

var v = [];
a.push("hello world");
console.log(b.length); // print 1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接