Как инициализировать длину массива в javascript?

Большинство учебных пособий, которые я читал на массивах в JavaScript (включая w3schools и devguru) предполагают, что вы можете инициализировать массив с определенной длиной, передав целое число в конструктор Array с использованием синтаксиса var test = new Array(4);.

После использования этого синтаксиса в моих 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;

Ответ 1

  • Почему вы хотите инициализировать длину? Теоретически в этом нет необходимости. Это может даже привести к запутанному поведению, потому что все тесты, использующие length, чтобы выяснить, пуст ли массив или нет, будут сообщать, что массив не пуст.
    Некоторые тесты показывают, что установка начальной длины больших массивов может быть более эффективными, если массив заполняется впоследствии, но прирост производительности (если таковой имеется), по-видимому, отличается от браузера к браузеру.

  • jsLint не нравится new Array(), потому что конструктор неоднозначен.

    new Array(4);
    

    создает пустой массив длины 4. Но

    new Array('4');
    

    создает массив , содержащий значение '4'.

Относительно вашего комментария: в JS вам не нужно инициализировать длину массива. Он растет динамично. Вы можете просто сохранить длину в некоторой переменной, например.

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

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

Ответ 2

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

Ответ 3

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

Можно удалить 0 в .fill() и запустить без аргументов, что заполнит массив undefined. (Тем не менее, это потерпит неудачу в Typescript)

Ответ 4

Самый короткий:

[...Array(1000)]

Ответ 5

[...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) => {} )

ИЛИ ЖЕ

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

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

(машинописный сейф)


Создание вложенных массивов

При создании 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], [ ], [ ]]

Таким образом, массив 3х2 будет выглядеть примерно так:

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

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

Инициализировать шахматную доску

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

Ответ 6

ES6 представляет Array.from который позволяет вам создавать Array из любых "подобных массиву" или итерируемых объектов:

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

В этом случае {length: 10} представляет минимальное определение "подобного массиву" объекта: пустой объект с определенным только свойством length.

Array.from позволяет использовать второй аргумент для отображения результирующего массива.

Ответ 7

Это приведет к инициализации свойства length до 4:

var x = [,,,,];

Ответ 8

Я удивлен, что не было предложено функциональное решение, позволяющее задать длину в одной строке. Следующее основано на UnderscoreJS:

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

По причинам, упомянутым выше, я бы избегал делать это, если бы я не хотел инициализировать массив до определенного значения. Интересно отметить, что существуют другие библиотеки, которые реализуют диапазон, включая Lo-dash и Lazy, которые могут иметь разные характеристики производительности.

Ответ 9

(вероятно, это было лучше, чем комментарий, но слишком длинный)

Итак, после прочтения этого мне было любопытно, было ли предварительное выделение на самом деле быстрее, потому что теоретически это должно быть. Тем не менее, этот блог дал несколько советов, направленных против него 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

Ответ 10

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

Ответ 11

Пожалуйста, люди пока не бросают ваши старые привычки. Существует большая разница в скорости между выделением памяти один раз, затем работой с записями в этом массиве (как в старом), и распределением ее многократно по мере роста массива (что неизбежно то, что система делает под капотом с другими предлагаемыми методами),

Конечно, все это не имеет значения, пока вы не захотите сделать что-нибудь классное с большими массивами. Тогда это так.

Поскольку в данный момент в 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;}

довольно быстро (около 50 мс для 10000, учитывая, что при n = 1000000 это заняло около 5 секунд), и

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

более чем за минуту (около 90 секунд для 10000 на той же хромированной консоли или примерно в 2000 раз медленнее). Это будет не только распределение, но и 10000 нажатий на цикл и т.д.

Ответ 12

Вот еще одно решение

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

Первый аргумент apply() - это привязка этого объекта, о котором нас здесь не заботят, поэтому мы устанавливаем его на null.

Array.apply(..) вызывает функцию Array(..) и раскрывает значение объекта { length: 3 } в качестве своих аргументов.

Ответ 13

Конструктор массива имеет неоднозначный синтаксис, а JSLint просто повредит вашим чувствам.

Кроме того, ваш примерный код сломан, второй оператор var поднимет значение SyntaxError. Вы устанавливаете свойство length массива test, поэтому нет необходимости в другом var.

Что касается ваших вариантов, array.length является единственным "чистым". Вопрос в том, почему вам нужно установить размер в первую очередь? Попробуйте реорганизовать свой код, чтобы избавиться от этой зависимости.

Ответ 14

Как объяснялось выше, использование new Array(size) несколько опасно. Вместо того, чтобы напрямую использовать его, поместите его в "функцию создателя массива". Вы можете легко убедиться, что эта функция недоступна, и вы избегаете опасности прямого вызова new Array(size). Кроме того, вы можете дать ему необязательное начальное значение по умолчанию. Эта функция createArray выполняет именно это:

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

Ответ 15

Предполагая, что длина массива постоянна. В Javascript это то, что мы делаем:

const intialArray = new Array(specify the value);

Ответ 16

Причина, по которой вы не должны использовать new Array, демонстрируется этим кодом:

var Array = function () {};

var x = new Array(4);

alert(x.length);  // undefined...

Некоторый другой код может испортиться с переменной Array. Я знаю, что это немного далека от того, что кто-нибудь напишет такой код, но все же...

Кроме того, как сказал Феликс Кинг, интерфейс немного непоследовательный и может привести к некоторым очень сложным ошибкам.

Если вам нужен массив с длиной = x, заполненный undefined (как это сделал бы new Array(x)), вы можете сделать это:

var x = 4;
var myArray = [];
myArray[x - 1] = undefined;

alert(myArray.length); // 4

Ответ 17

Вы можете задать длину массива с помощью array.length = youValue

Итак, это будет

var myArray = [];
myArray.length = yourValue;