В чем разница между «Array ()» и «[]» при объявлении массива JavaScript?


841

В чем реальная разница между объявлением массива следующим образом:

var myArray = new Array();

а также

var myArray = [];

[]лексем: ARRAY_INIT; new Arrayжетоны: NEW, IDENTIFIER; new Array()жетоны:NEW, IDENTIFIER, CALL
noobninja

Ответы:


952

Разница есть, но в этом примере нет разницы.

Использование более подробного метода: 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()вы можете установить размер массива, который влияет на размер стека. Это может быть полезно, если вы получаете переполнение стека ( Performance of Array.push vs Array.unshift ), что происходит, когда размер массива превышает размер стека, и его необходимо создать заново. Таким образом, на самом деле, в зависимости от варианта использования, может быть увеличение производительности при использовании, new Array()потому что вы можете предотвратить переполнение.

Как указано в этом ответе , на new Array(5)самом деле не будет добавлять пять undefinedэлементов в массив. Это просто добавляет место для пяти предметов. Помните, что использование Arrayэтого способа затрудняет использование array.lengthрасчетов.


66
Это немного неправильно. Есть одно очень важное различие между новыми Array () и [], которое я укажу в своем ответе.
coderjoe

30
Но, как отмечено в вашем ответе, все будет иначе, если вы полностью сошли с ума и перезаписали функцию Array ..?
Ник

19
Что ж, важно то, что использование оператора new заставляет интерпретатор предпринимать всевозможные дополнительные шаги для перехода в глобальную область видимости, поиска конструктора, вызова конструктора и назначения результата ... что в большинстве случаев будет Массив времени выполнения. Вы можете избежать накладных расходов на поиск глобального конструктора, просто используя []. Это может показаться небольшим, но когда вы снимаете в приложении практически в режиме реального времени, это может иметь значение.
coderjoe

5
Существует огромная разница в производительности: jsperf.com/create-an-array-of-initial-size/2
Марко Луглио

4
Правда, но вам также не нужны точки с запятой или разрывы строк в большинстве мест, где я их добавляю. Это о последовательности и разборчивости. Вы знаете, ИМХО.
Nickf

774

Разница между созданием массива с неявным массивом и конструктором массива невелика, но важна.

Когда вы создаете массив с помощью

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().

Лучше всего просто использовать, []если вы знаете, что хотите просто массив. Я также не предлагаю идти вокруг и переопределять Массив ...


157
Ну, приятно знать, я полагаю. Какой человек будет перезаписывать класс массива, я не знаю ...
nickf

160
Ты абсолютно прав. Только сумасшедший может перезаписать класс массива. Теперь уделите немного времени и рассмотрите всю дополнительную работу, используя new Array (), которую переводчик выполняет для поддержки этих безумцев. Я просто избегаю всего этого вместе с [].
кодерджо

51
Хороший пример такого глобального загрязнения, которое возможно с JavaScript.
Дэвид Снабел-Каунт

8
Стоит отметить, что новый массив (размер) быстрее, чем другие возможные методы, использующие нотацию []. Источник: jsperf.com/create-an-array-of-initial-size/2
Марко Луглио

9
К сожалению, этот тест неправильно подготовлен. Он тестирует инициализацию массива с инициализацией массивов с последующим доступом к массиву. Нет никакого контроля, чтобы доказать, что браузеры на самом деле предварительно выделяют память (что не указано в спецификации). Если мы можем предположить, что доступ к массиву является постоянным и большая часть времени будет потрачена на выделение памяти в обоих примерах, тогда [] может быть предпочтительнее, если вы создаете экземпляры миллионов массивов. jsperf.com/array-instanciation
coderjoe

95

Есть важное отличие, о котором пока не упоминается ни один ответ.

Из этого:

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

22
Твой единственный фактический ответ
Виктор

Это имеет смысл, я только что натолкнулся на другую конструкцию, для которой я не могу найти документированные ссылки: [...Array(2)]которая эквивалентна [undefined, undefined]с точки зрения результатов.
Роберто Андраде

Похоже, что ответ на мои предыдущие комментарии - «Оператор спреда»: javascript.info/rest-parameters-spread-operator
Роберто Андраде,

@RobertoAndrade, который имеет смысл, потому что оператору распространения нужно будет считывать записи, чтобы он мог применить такое копирование ... и чтение такого пустого слота возвращает undefinedкак обычно.
Хакс

51

Как ни странно, new Array(size)это почти в 2 раза быстрее, чем []в Chrome, и примерно столько же в FF и IE (измеряется путем создания и заполнения массива). Это имеет значение, только если вы знаете приблизительный размер массива. Если вы добавите больше элементов, чем указали длину, повышение производительности будет потеряно.

Точнее: Array(быстрая операция с постоянным временем, которая не выделяет память, тогда []как операция с линейным временем, которая устанавливает тип и значение.


3
Я много тестировал в Node.js: когда вам нужно поместить некоторое количество элементов в массив, new Array(length)на 0 <= размер <= ~ 1000, на размер> ~ 1000 побед[]
glukki

1
проверить это stackoverflow.com/questions/7375120/...
Xsmael

40

Для получения дополнительной информации на следующей странице описано, почему вам никогда не нужно использоватьnew Array()

Вам никогда не нужно использовать new Object()в JavaScript. {} Вместо этого используйте литерал объекта . Точно так же не используйте new Array(), [] вместо этого используйте литерал массива . Массивы в JavaScript не работают так же, как массивы в Java, и использование Java-подобного синтаксиса вас смущает.

Не используйте new Number, new Stringили new Boolean. Эти формы создают ненужные обертки объектов. Просто используйте простые литералы вместо этого.

Также ознакомьтесь с комментариями - new Array(length)форма не служит какой-либо полезной цели (по крайней мере, в сегодняшних реализациях JavaScript).


3
Крокфорд также говорит, что следует использовать [], а не новый Array (). К сожалению, он не говорит, почему в связанной статье. Я предполагаю, что это просто вопрос пространства и скорости. javascript.crockford.com/code.html
Носредна

4
Крокфорд не фанат использования ключевого слова «new» для создания нового экземпляра объекта в Javascript. В лекциях он заявил, что он верит, что это создает двусмысленность и не вписывается в наследство стиля прототипа Javascript. Он конкретно обращается к созданным пользователем конструкторам объектов, но, учитывая это убеждение, легко понять, почему он бы порекомендовал вам не использовать его со встроенными модулями, когда есть альтернативный синтаксис.
Алан Сторм

@Alan Storm: по крайней мере для Number, String и Boolean он говорит, что «эти формы создают ненужные обертки объектов», но я думаю, что это не относится к массиву.
BarelyFitz

10

Для того, чтобы лучше понять []и 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

Вышеуказанный результат получен из консоли Google Chrome в Windows 7.


4
но почему [] == [] или [] === [] ложно?
ана

5
«Выражение, сравнивающее Объекты, истинно, только если операнды ссылаются на один и тот же Объект». (источник: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
ср.

Этот ответ вишня выбирает примеры, чтобы подразумевать, что эти две конструкции идентичны. Другие посты на этой странице указывают на различия, такие как Array(3)или new Array(3)не такие, как [3].
ggorlen

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

cdmckay - это неправильно. var a = [5] будет массивом с одним элементом - числом пять.
BarelyFitz

2
@BarelyFitz: Я так и сказал. В ответе Богдана он говорит, что вызов конструктора нельзя использовать для инициализации массива, но он ошибся. Мой комментарий был только для того, чтобы уточнить, что вы не можете использовать вызов конструктора для инициализации массива одного элемента.
cdmckay

1
@ cdmckay: извините, я неправильно понял ваш комментарий. Для пояснения: new Array (arg) - если arg является числовым, это создает пустой массив с длиной = arg; new Array (arg1, arg2) - создает новый массив и инициализирует элементы массива. Поэтому, если вы хотите создать массив с одним числовым элементом, подобным [5], вы не можете сделать это, используя new Array (5). Но на самом деле вы никогда не должны использовать новый Array (), так что это спорный вопрос.
BarelyFitz

5

Я могу объяснить более конкретно, начиная с этого примера, основанного на хорошем примере Фредрика.

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

Я просто добавил еще одно значение в массивы и сделал четыре предупреждения: первое и второе - дать нам значение, хранящееся в каждом массиве, чтобы быть уверенным в значениях. Они вернутся так же! Теперь попробуйте третий, он возвращает ложь, потому что

JS рассматривает test1 как переменную с типом данных массива , и он рассматривает test2 как объект с функциональностью массива , и здесь есть несколько небольших различий.

Первое отличие в том, что когда мы вызываем test1, он вызывает переменную, не задумываясь, он просто возвращает значения, которые хранятся в этой переменной, независимо от ее типа данных! Но, когда мы называем test2 он вызывает Array () функцию , а затем он хранит наши «Толкаемые» значения в «Значение» собственности, и то же самое происходит , когда мы начеку test2, он возвращает «Value» свойство объекта массива.

Поэтому, когда мы проверяем, равно ли test1 равен test2, они, конечно, никогда не вернут true, один - функция, а другой - переменная (с типом массива), даже если они имеют одинаковое значение!

Чтобы быть уверенным в этом, попробуйте 4-е предупреждение с добавлением .value; это вернет истину. В этом случае мы сообщаем JS «Независимо от типа контейнера, будь то функция или переменная, сравните значения, хранящиеся в каждом контейнере, и скажите нам, что вы видели!» именно так и происходит.

Надеюсь, я четко сформулировал эту идею, и извините за мой плохой английский.


19
Удивительно, что за такую ​​полную и полную ерунду проголосовали. Сравнение между массивами будет ложным независимо от того, как вы их создадите, потому что оно сравнивает идентичность объекта, а они - разные объекты. Массивы не имеют значения свойства. []и new Array()идентичен; .valueбудет undefinedв обоих случаях, и сравнение их всегда будет ложным.
Сликц

Согласитесь, этот ответ не имеет смысла и ничего не показывает. Там нет такой вещи, как array.value. и то и другое typeof []и typeof new Array()вернуть object. Это одна из причин, почему существует функция с именемArray.isArray
gman

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

против

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

3

Первый - это конструктор объекта по умолчанию call.most, используемый для динамических значений.

var array = new Array(length); //initialize with default length

второй массив используется при создании статических значений

var array = [red, green, blue, yellow, white]; // this array will contain values.

3

Большой разницы нет, они в основном делают одно и то же, но делают это по-разному, но читайте дальше, посмотрите на это утверждение на W3C:

var cars = ["Saab", "Volvo","BMW"];

а также

var cars = new Array("Saab", "Volvo", "BMW");

Два приведенных выше примера делают то же самое. Нет необходимости использовать новый Array ().
Для простоты, читабельности и скорости выполнения используйте первый (метод литерала массива).

Но в то же время создание нового массива с использованием new Arrayсинтаксиса считается плохой практикой:

Избегайте нового массива ()

Нет необходимости использовать встроенный в JavaScript конструктор массива new Array ().
Вместо этого используйте [].
Эти два разных оператора создают новый пустой массив с именем points:

var points = new Array();         // Bad
var points = [];                  // Good 

Эти два разных оператора создают новый массив, содержащий 6 чисел:

var points = new Array(40, 100, 1, 5, 25, 10); // Bad    
var points = [40, 100, 1, 5, 25, 10];          // Good

Новое ключевое слово только усложняет код. Это также может привести к неожиданным результатам:

var points = new Array(40, 100);  // Creates an array with two elements (40 and 100)

Что если я удалю один из элементов?

var points = new Array(40);       // Creates an array with 40 undefined elements !!!!!

Таким образом, в принципе не считается лучшей практикой, также есть одно небольшое отличие, вы можете передать длину, new Array(length)как это, что также не рекомендуется.


Привет Алиреза, они скопированы и вставлены откуда-то? Пожалуйста, добавьте ссылку на страницу, откуда текст копируется. Смотрите эту страницу справочного центра для деталей. Спасибо.
Панг

Полезно дляnew Array(40).fill(123)
gman

2

Разница в использовании

var arr = new Array(size);

Или

arr = [];
arr.length = size;

Как достаточно обсуждалось в этом вопросе.

Я хотел бы добавить вопрос скорости - текущий быстрый путь, на google chromeвторой один.

Но обратите внимание, эти вещи, как правило, сильно меняются с обновлениями. Также время выполнения будет отличаться в разных браузерах.

Например, второй вариант, который я упомянул, работает со скоростью 2 миллиона [операций в секунду] chrome, но если вы попробуете его, mozilla dev.вы получите удивительно более высокий показатель - 23 миллиона.

В любом случае, я бы посоветовал вам проверять это время от времени на разных браузерах (и машинах), используя сайт как таковой.


2

Как я знаю, различие вы можете найти срез (или другие функции массива), такие как code1. И code2 показывают u Array и его экземпляры :

code1:

[].slice; // find slice here
var arr = new Array();
arr.slice // find slice here
Array.prototype.slice // find slice here

code2:

[].__proto__ == Array.prototype; // true
var arr = new Array();
arr.__proto__ == Array.prototype; // true

вывод:

как вы можете видеть []и new Array()создавать новый экземпляр Array. И все они получают функции прототипа изArray.prototype

Они просто разные экземпляры Array.so это объясняет, почему [] != []

:)


2

Я столкнулся со странным поведением, используя [].

У нас есть «классы» модели с полями, инициализированными до некоторого значения. Например:

require([
  "dojo/_base/declare",
  "dijit/_WidgetBase",
], function(declare, parser, ready, _WidgetBase){

   declare("MyWidget", [_WidgetBase], {
     field1: [],
     field2: "",
     function1: function(),
     function2: function()
   });    
});

Я обнаружил, что когда поля инициализируются, []тогда они будут общими для всех объектов модели. Внесение изменений в один влияет на всех остальных.

Этого не происходит, инициализируя их new Array(). То же самое для инициализации объектов ( {}против новых Object())

TBH Я не уверен, если это проблема с фреймворком, который мы использовали ( Dojo )


2

Это больше, чем кажется на первый взгляд. Большинство других ответов верны, НО ТАКЖЕ ..

new Array(n)

  • Позволяет двигателю перераспределять пространство для nэлементов
  • Оптимизирован для создания массива
  • Созданный массив помечается как разреженный, который имеет наименее производительные операции с массивами, потому что каждый доступ к индексу должен проверять границы, видеть, существует ли значение и проходить цепочку прототипов.
  • Если массив помечен как разреженный, обратного пути нет (по крайней мере, в V8), он всегда будет медленнее в течение своей жизни, даже если вы заполняете его содержимым (упакованный массив) спустя 1 мс или 2 часа, не имеет значения

[1, 2, 3] || []

  • Созданный массив помечается упакованным (если вы не используете deleteили [1,,3]синтаксис)
  • Оптимизированный для массива операций ( for .., forEach, mapи т.д.)
  • Двигатель должен перераспределить пространство по мере роста массива

Это, вероятно , не относится к более старым версиям / браузерам.


-2

Я обнаружил одно различие между двумя конструкциями, которое меня сильно укусило.

Допустим, у меня есть:

function MyClass(){
  this.property1=[];
  this.property2=new Array();
};
var MyObject1=new MyClass();
var MyObject2=new MyClass();

В реальной жизни, если я делаю это:

MyObject1.property1.push('a');
MyObject1.property2.push('b');
MyObject2.property1.push('c');
MyObject2.property2.push('d');

В итоге я получаю вот что:

MyObject1.property1=['a','c']
MyObject1.property2=['b']
MyObject2.property1=['a','c']
MyObject2.property2=['d']

Я не знаю, что должно произойти в спецификации языка, но если я хочу, чтобы мои два объекта имели уникальные массивы свойств в моих объектах, я должен использовать new Array().


Этот JSFiddle показывает, что выходной результат - это то, что вы ожидаете, используя литерал массива []и new Array()конструктор, что приводит к одному элементу на массив на свойство. В вашем коде должно быть что-то еще, чтобы в итоге вы получили результат, показанный выше.
Gfullam

Баки, это не происходит для меня, в любом браузере. Чтобы получить такое поведение, вы должны сделать что-то вроде этого: var property1static=[]; function MyClass(){ this.property1=property1static; this.property2=new Array(); };
Дейв Бертон

-3

Использование конструктора Array создает новый массив требуемой длины и заполняет каждый из индексов неопределенным, назначенный массив переменной создает индексы, для которых вы предоставляете ему информацию.


1
Нет, массив НЕ заполнен, внутри нет индексов / ключей. Например .forEach не будет работать.
CFrei
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.