Самый эффективный способ создать массив JavaScript с нулевым заполнением?

Каков наиболее эффективный способ создания массива произвольной длины с нулевым заполнением в JavaScript?

47 ответов

ES6 вводит Array.prototype.fill, Это можно использовать так:

new Array(len).fill(0);

Не уверен, что это быстро, но мне это нравится, потому что это коротко и самоописательно.

Это все еще не в IE ( проверьте совместимость), но есть доступный polyfill.

Хотя это старая ветка, я хотел добавить к ней свои 2 цента. Не уверен, насколько это медленно / быстро, но это быстрый лайнер. Вот что я делаю:

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

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]

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

Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]

Другие ответы предложили:

new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]

но если вы хотите 0 (число), а не "0" (ноль внутри строки), вы можете сделать:

new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]

SHORTEST

Array(n).fill(0)

(16 знаков), где n это размер массива


2018.10.28 я сделал сравнение производительности 15 предложений из других ответов. Тестирование проводилось на Mac OS X 10.13.6 High Sierra, в трех браузерах: Chrome 69.0.3497, Safari 12.0 (13606.2.11) и Firefox 63.0 (64-разрядная версия).

Результат для n=100000

Ниже я показываю результаты для самого быстрого браузера (сафари):

введите описание изображения здесь введите описание изображения здесь

Для всех браузеров самым быстрым решением было M - однако это не "типичный массив" (но очень быстрый) - Safari 33,8 тыс. Операций в секунду, Chrome 5,2 тыс., FF 3,5 тыс.,

Самые быстрые решения для типичных массивов:

  • A и B (было похоже) для Safari 5.5k и Chrome 1.1k (для Firefox A 0.1k, B 0.06k)
  • F для Firefox 0.6k (в Safari 3.1k, Chrome 1.1k)
  • для Chrome и Safari A, B, F результаты были близки

Самое медленное решение:

  • G для Safari 0.02k и Firefox 0.04k (для Chrome 0.1k)
  • D для Chrome 0.04k (на Safari 0.33k, на Firefox 0.15k)

Решение N работает только на Firefox и Chrome.

Результат для n=10

Самый быстрый:

  • M был самым быстрым на Chrome 17.3M и Safari 13.3M (Firefox 4.7M)
  • A, B были похожи и быстрее всего на Firefox 16,9M (Chrome 15,6M, Safari 3,5M)

Slowest:

  • O для Safari 0,35M
  • K для Chrome 0.35M
  • N для Firefox 0.31M

ЗАКЛЮЧЕНИЕ

  • самое быстрое решение во всех браузерах (кроме маленьких n на Firefox) был М let a = floar32array(n) (однако это не типичный массив) - для него самым быстрым браузером был Safari (для больших n > В 6 раз быстрее, чем Chrome, > в 9 раз быстрее, чем Firefox)
  • для типичных массивов предпочтительным решением является А let a = Array(n).fill(0) (быстрый и короткий код)

Вы можете выполнить тестирование на вашей машине здесь.

Элегантный способ заполнить массив предварительно вычисленными значениями

Вот еще один способ сделать это с помощью ES6, о котором никто еще не упоминал:

> Array.from(Array(3), () => 0)
< [0, 0, 0]

Это работает, передавая функцию карты в качестве второго параметра Array.from,

В приведенном выше примере первый параметр выделяет массив из 3 позиций, заполненный значением undefined а затем лямбда-функция отображает каждый из них на значение 0,

Хотя Array(len).fill(0) короче, это не сработает, если вам нужно сначала заполнить массив, выполнив какое-то вычисление (я знаю, что вопрос не задавался, но многие в конечном итоге ищут это).

Например, если вам нужен массив с 10 случайными числами:

> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]

Это более кратко (и элегантно), чем эквивалент:

const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
    numbers[i] = Math.round(10 * Math.random());
}

Этот метод также можно использовать для генерации последовательностей чисел, используя параметр индекса, предоставленный в обратном вызове:

> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Бонусный ответ: заполнить массив с помощью String repeat()

Поскольку этот ответ привлекает много внимания, я также хотел показать этот крутой трюк. Хотя и не такой полезный, как мой основной ответ, представлю еще не очень известную, но очень полезную строку repeat() метод. Вот хитрость:

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

Круто, да? repeat() Это очень полезный метод для создания строки, которая является повторением исходной строки определенное количество раз. После этого, split() создает для нас массив, который затем map() следуйте ценностям, которые мы хотим. Разбивая его по шагам:

> "?".repeat(10)
< "??????????"

> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

Уже упомянутый метод заполнения ES 6 прекрасно справляется с этой задачей. Большинство современных настольных браузеров уже поддерживают требуемые методы-прототипы Array (Chromium, FF, Edge и Safari) [ 1]. Вы можете посмотреть детали на MDN. Простой пример использования

a = new Array(10).fill(0);

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

Примечание добавлено в августе 2013 года, обновлено в феврале 2015 года. Нижеприведенный ответ от 2009 года относится к универсальному JavaScript Array тип. Это не относится к новым типизированным массивам, определенным в ES2015 [и доступным сейчас во многих браузерах], например Int32Array и тому подобное. Также обратите внимание, что ES2015 добавляет fill метод для массивов и типизированных массивов, который, вероятно, будет наиболее эффективным способом их заполнения...

Кроме того, для некоторых реализаций это может иметь большое значение для создания массива. В частности, движок Chrome V8 пытается использовать высокоэффективный массив непрерывной памяти, если сочтет это возможным, переходя на массив на основе объектов только при необходимости.


В большинстве языков это будет предварительно выделено, а затем заполнено нулями, например так:

function newFilledArray(len, val) {
    var rv = new Array(len);
    while (--len >= 0) {
        rv[len] = val;
    }
    return rv;
}

Но JavaScript-массивы на самом деле не являются массивами, они представляют собой сопоставления ключ / значение, как и все другие объекты JavaScript, поэтому нет необходимости делать "предварительное выделение" (установка длины не выделяет столько слотов для заполнения), ни есть ли основания полагать, что выгода от обратного отсчета (то есть для быстрого сравнения в цикле) не перевешивается добавлением ключей в обратном порядке, когда реализация, возможно, хорошо оптимизировала их обработку ключей связанные с массивами по теории, вы обычно будете делать их по порядку.

Фактически, Мэтью Крамли отметил, что обратный отсчет в Firefox заметно медленнее, чем подсчет, и я могу подтвердить этот результат - это часть массива (цикл до нуля все же быстрее, чем до предела в переменной). Очевидно, что добавление элементов в массив в обратном порядке является медленной операцией в Firefox. На самом деле, результаты могут сильно отличаться от реализации JavaScript (что не так уж и удивительно). Вот быстрая и грязная тестовая страница (ниже) для реализаций браузера (очень грязная, не дает результатов во время тестов, поэтому обеспечивает минимальную обратную связь и будет работать вне временных рамок скрипта). Я рекомендую освежиться между тестами; FF (по крайней мере) замедляет повторные тесты, если вы этого не сделаете.

Довольно сложная версия, в которой используется Array#concat, работает быстрее, чем прямая инициализация в FF, где-то между 1000 и 2000 массивами элементов. На двигателе Chrome V8, однако, прямой init побеждает каждый раз...

Вот тестовая страница ( живая копия):

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
    font-family:    sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
.error {
    color:      red;
}
.winner {
    color:      green;
    font-weight:    bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
    'downpre':  {
        total:  0,
        desc:   "Count down, pre-decrement",
        func:   makeWithCountDownPre
    },
    'downpost': {
        total:  0,
        desc:   "Count down, post-decrement",
        func:   makeWithCountDownPost
    },
    'up':       {
        total:  0,
        desc:   "Count up (normal)",
        func:   makeWithCountUp
    },
    'downandup':  {
        total:  0,
        desc:   "Count down (for loop) and up (for filling)",
        func:   makeWithCountDownArrayUp
    },
    'concat':   {
        total:  0,
        desc:   "Concat",
        func:   makeWithConcat
    }
};

document.observe('dom:loaded', function() {
    var markup, defname;

    markup = "";
    for (defname in testdefs) {
        markup +=
            "<div><input type='checkbox' id='chk_" + defname + "' checked>" +
            "<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
    }
    $('checkboxes').update(markup);
    $('btnTest').observe('click', btnTestClick);
});

function epoch() {
    return (new Date()).getTime();
}

function btnTestClick() {

    // Clear log
    $('log').update('Testing...');

    // Show running
    $('btnTest').disabled = true;

    // Run after a pause while the browser updates display
    btnTestClickPart2.defer();
}
function btnTestClickPart2() {

    try {
        runTests();
    }
    catch (e) {
        log("Exception: " + e);
    }

    // Re-enable the button; we don't yheidl
    $('btnTest').disabled = false;
}

function runTests() {
    var start, time, counter, length, defname, def, results, a, invalid, lowest, s;

    // Get loops and length
    s = $F('txtLoops');
    runcount = parseInt(s);
    if (isNaN(runcount) || runcount <= 0) {
        log("Invalid loops value '" + s + "'");
        return;
    }
    s = $F('txtLength');
    length = parseInt(s);
    if (isNaN(length) || length <= 0) {
        log("Invalid length value '" + s + "'");
        return;
    }

    // Clear log
    $('log').update('');

    // Do it
    for (counter = 0; counter <= runcount; ++counter) {

        for (defname in testdefs) {
            def = testdefs[defname];
            if ($('chk_' + defname).checked) {
                start = epoch();
                a = def.func(length);
                time = epoch() - start;
                if (counter == 0) {
                    // Don't count (warm up), but do check the algorithm works
                    invalid = validateResult(a, length);
                    if (invalid) {
                        log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
                        return;
                    }
                }
                else {
                    // Count this one
                    log("#" + counter + ": " + def.desc + ": " + time + "ms");
                    def.total += time;
                }
            }
        }
    }

    for (defname in testdefs) {
        def = testdefs[defname];
        if ($('chk_' + defname).checked) {
            def.avg = def.total / runcount;
            if (typeof lowest != 'number' || lowest > def.avg) {
                lowest = def.avg;
            }
        }
    }

    results =
        "<p>Results:" +
        "<br>Length: " + length +
        "<br>Loops: " + runcount +
        "</p>";
    for (defname in testdefs) {
        def = testdefs[defname];
        if ($('chk_' + defname).checked) {
            results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
        }
    }
    results += "<hr>";
    $('log').insert({top: results});
}

function validateResult(a, length) {
    var n;

    if (a.length != length) {
        return "Length is wrong";
    }
    for (n = length - 1; n >= 0; --n) {
        if (a[n] != 0) {
            return "Index " + n + " is not zero";
        }
    }
    return undefined;
}

function makeWithCountDownPre(len) {
    var a;

    a = new Array(len);
    while (--len >= 0) {
        a[len] = 0;
    }
    return a;
}

function makeWithCountDownPost(len) {
    var a;

    a = new Array(len);
    while (len-- > 0) {
        a[len] = 0;
    }
    return a;
}

function makeWithCountUp(len) {
    var a, i;

    a = new Array(len);
    for (i = 0; i < len; ++i) {
        a[i] = 0;
    }
    return a;
}

function makeWithCountDownArrayUp(len) {
    var a, i;

    a = new Array(len);
    i = 0;
    while (--len >= 0) {
        a[i++] = 0;
    }
    return a;
}

function makeWithConcat(len) {
    var a, rem, currlen;

    if (len == 0) {
        return [];
    }
    a = [0];
    currlen = 1;
    while (currlen < len) {
        rem = len - currlen;
        if (rem < currlen) {
            a = a.concat(a.slice(0, rem));
        }
        else {
            a = a.concat(a);
        }
        currlen = a.length;
    }
    return a;
}

function log(msg) {
    $('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>

Если вы используете ES6, вы можете использовать Array.from() следующим образом:

Array.from({ length: 3 }, () => 0);
//[0, 0, 0]

Имеет тот же результат, что и

Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]

Так как

Array.from({ length: 3 })
//[undefined, undefined, undefined]

По умолчанию Uint8Array, Uint16Array а также Uint32Array классы хранят нули в качестве своих значений, поэтому вам не нужны никакие сложные методы заполнения, просто сделайте:

var ary = new Uint8Array(10);

все элементы массива ary будут нули по умолчанию.

function makeArrayOf(value, length) {
  var arr = [], i = length;
  while (i--) {
    arr[i] = value;
  }
  return arr;
}

makeArrayOf(0, 5); // [0, 0, 0, 0, 0]

makeArrayOf('x', 3); // ['x', 'x', 'x']

Обратите внимание, что while обычно более эффективен, чем for-in, forEach, так далее.

Используя обозначение объекта

var x = [];

ноль заполнен? лайк...

var x = [0,0,0,0,0,0];

заполнено "неопределенным"...

var x = new Array(7);

объективная запись с нулями

var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;

В качестве примечания, если вы измените прототип Array, оба

var x = new Array();

а также

var y = [];

будет иметь эти модификации прототипа

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

Я проверил все комбинации предварительного выделения / отсутствия предварительного выделения, счета вверх / вниз и циклов for / while в IE 6/7/8, Firefox 3.5, Chrome и Opera.

Приведенные ниже функции всегда были самыми быстрыми или чрезвычайно близкими в Firefox, Chrome и IE8, и не намного медленнее, чем самые быстрые в Opera и IE 6. Это также самый простой и понятный, на мой взгляд. Я нашел несколько браузеров, в которых версия цикла while немного быстрее, поэтому я включил ее и для справки.

function newFilledArray(length, val) {
    var array = [];
    for (var i = 0; i < length; i++) {
        array[i] = val;
    }
    return array;
}

или же

function newFilledArray(length, val) {
    var array = [];
    var i = 0;
    while (i < length) {
        array[i++] = val;
    }
    return array;
}

const arr = Array.from({ length: 10 }).fill(0)

Решение ES6:

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

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

Например (используя функцию из выбранного ответа выше для инициализации массива), создайте заполненный нулями массив длины maxLength, как переменную, видимую для кода, который требует нулевых массивов:

var zero = newFilledArray(maxLength, 0);

Теперь нарезайте этот массив каждый раз, когда вам нужен заполненный нулями массив длины requiredLength < maxLength:

zero.slice(0, requiredLength);

Во время выполнения моего кода я создавал массивы, заполненные нулями, тысячи раз, что значительно ускорило процесс.

function zeroFilledArray(size) {
    return new Array(size + 1).join('0').split('');
}

Используя lodash или подчеркивание

_.range(0, length - 1, 0);

Или, если у вас есть массив, и вы хотите массив такой же длины

array.map(_.constant(0));

Я ничего не имею против:

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);

предложенный Zertosh, но в новых расширениях массива ES6 вы можете сделать это изначально с fill метод. Теперь IE edge, Chrome и FF его поддерживают, но проверьте таблицу совместимости

new Array(3).fill(0) дам тебе [0, 0, 0], Вы можете заполнить массив любым значением, например new Array(5).fill('abc') (даже объекты и другие массивы).

Кроме того, вы можете изменить предыдущие массивы с помощью fill:

arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5)  # what to fill, start, end

который дает вам: [1, 2, 3, 9, 9, 6]

Создать новый массив

new Array(arrayLength).fill(0);

Чтобы добавить некоторые значения в конце существующего массива

[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]

пример

//**To create an all new Array**

console.log(new Array(5).fill(0));

//**To add some values at the end of an existing Array**

let existingArray = [1,2,3]

console.log([...existingArray, ...new Array(5).fill(0)]);

То, как я обычно это делаю (и удивительно быстро) использует Uint8Array, Например, создавая заполненный нулями вектор из 1M элементов:

  var zeroFilled = [].slice.apply(new Uint8Array(1000000))

Я пользователь Linux и всегда работал на меня, но однажды у друга, использующего Mac, было несколько ненулевых элементов. Я думал, что его машина работает со сбоями, но все же вот самый безопасный способ, который мы нашли, это исправить:

  var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000)) 

отредактированный

Chrome 25.0.1364.160

  1. Фредерик Готлиб - 6,43
  2. Сэм Барнум - 4.83
  3. Эли - 3,68
  4. Иисус Навин 2,91
  5. Мэтью Крамли - 2,67
  6. бдуран - 2,55
  7. Аллен Райс - 2.11
  8. Кангакс - 0,68
  9. Tj. Краудер - 0,67
  10. Зертош - ОШИБКА

Firefox 20.0

  1. Аллен Райс - 1,85
  2. Джошуа - 1,82
  3. Мэтью Крамли - 1,79
  4. бдуран - 1,37
  5. Фредерик Готлиб - 0,67
  6. Сэм Барнум - 0,63
  7. Эли - 0,59
  8. кагакс - 0,13
  9. Tj. Краудер - 0,13
  10. Зертош - ОШИБКА

Отсутствует самый важный тест (по крайней мере, для меня): Node.js. Я подозреваю, что это близко к тесту Chrome.

Начиная с ECMAScript2016, существует один четкий выбор для больших массивов.

Поскольку этот ответ по-прежнему отображается в верхней части результатов поиска Google, вот ответ на 2017 год.

Вот текущий jsbench с несколькими десятками популярных методов, включая многие, предложенные до сих пор по этому вопросу. Если вы найдете лучший способ, пожалуйста, добавьте, раскошелиться и поделиться.

Я хочу отметить, что не существует истинного наиболее эффективного способа создания массива произвольной длины с нулевым заполнением. Вы можете оптимизировать скорость, ясность и ремонтопригодность - и то, и другое можно считать более эффективным выбором в зависимости от потребностей проекта.

При оптимизации по скорости вы хотите: создать массив с использованием буквального синтаксиса; установите длину, инициализируйте переменную итерации и выполните итерацию по массиву, используя цикл while. Вот пример.

const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
  arr[i] = 0;
  i++;
}

Другая возможная реализация будет:

(arr = []).length = n;
let i = 0;
while (i < n) {
    arr[i] = 0;
    i++;
}

Но я настоятельно не рекомендую использовать эту вторую имплантацию на практике, поскольку она менее понятна и не позволяет вам поддерживать область видимости для переменной массива.

Они значительно быстрее, чем заполнение цикла for, и примерно на 90% быстрее, чем стандартный метод

const arr = Array(n).fill(0);

Но этот метод заполнения все еще является наиболее эффективным выбором для небольших массивов из-за его ясности, краткости и удобства обслуживания. Разница в производительности, скорее всего, не убьет вас, если вы не создадите много массивов с длинами порядка тысяч и более.

Несколько других важных замечаний. Большинство руководств по стилю рекомендуют вам больше не использовать var без особых причин при использовании ES6 или новее. использование const для переменных, которые не будут переопределены и let для переменных, которые будут. MDN и Airbnb's Style Guide - отличные места для получения дополнительной информации о лучших практиках. Вопросы не касались синтаксиса, но важно, чтобы люди, плохо знакомые с JS, знали об этих новых стандартах при поиске среди множества старых и новых ответов.

Не видел этот метод в ответах, поэтому вот он:

"0".repeat( 200 ).split("").map( parseFloat )

В результате вы получите нулевой массив длины 200:

[ 0, 0, 0, 0, ... 0 ]

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

Как насчет new Array(51).join('0').split('')?

Я тестировал отличный ответ TJ Crowder и придумал рекурсивное слияние на основе решения concat, которое превосходит любое в его тестах в Chrome (я не тестировал другие браузеры).

function makeRec(len, acc) {
    if (acc == null) acc = [];
    if (len <= 1) return acc;
    var b = makeRec(len >> 1, [0]);
    b = b.concat(b);
    if (len & 1) b = b.concat([0]);
    return b;
},

вызвать метод с makeRec(29),

Моя самая быстрая функция была бы:

function newFilledArray(len, val) {
    var a = [];
    while(len--){
        a.push(val);
    }
    return a;
}

var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds

Использование встроенных функций push и shift для добавления элементов в массив намного быстрее (примерно в 10 раз), чем объявление области действия массива и обращение к каждому элементу для установки его значения.

К вашему сведению: я последовательно получаю более быстрые времена с первым циклом, который ведет обратный отсчет, при запуске этого в firebug (расширение firefox).

var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
    a.push(0);
    len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
    a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds

Мне интересно узнать, что делает из этого TJ Crowder?:-)

let filled = [];
filled.length = 10;
filled.fill(0);

console.log(filled);

new Array(7).fill(0) //Array with 7 zeros.

Самый короткий для кода цикла

a=i=[];for(;i<100;)a[i++]=0;

edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;

Безопасная версия вар

var a=[],i=0;for(;i<100;)a[i++]=0;

edit:
for(var i=100,a=[];i--;)a[i]=0;

Я знал, что у меня где-то был этот прото:)

Array.prototype.init = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this[n] = x; }
    return this;
}

var a = (new Array(5)).init(0);

var b = [].init(0,4);

Редактировать: тесты

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

Вот что я проверял:

//my original method
Array.prototype.init = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this[n] = x; }
    return this;
}

//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this.push(x); }
    return this;
}

//joshua's method
function newFilledArray(len, val) {
    var a = [];
    while(len--){
        a.push(val);
    }
    return a;
}

//test m1 and m2 with short arrays many times 10K * 10

var a = new Date();
for(var i=0; i<10000; i++)
{
    var t1 = [].init(0,10);
}
var A = new Date();

var b = new Date();
for(var i=0; i<10000; i++)
{
    var t2 = [].init2(0,10);
}
var B = new Date();

//test m1 and m2 with long array created once 100K

var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();

var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();

//test m3 with short array many times 10K * 10

var e = new Date();
for(var i=0; i<10000; i++)
{
    var t5 = newFilledArray(10,0);
}
var E = new Date();

//test m3 with long array created once 100K

var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();

Результаты:

IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412

FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8

Так что, по моим расчетам, push действительно медленнее, но лучше работает с более длинными массивами в FF, но хуже в IE, который просто отстой в целом (неожиданность кваля).

Это concat версия намного быстрее в моих тестах на Chrome (2013-03-21). Около 200 мс для 10000000 элементов против 675 для прямой инициализации.

function filledArray(len, value) {
    if (len <= 0) return [];
    var result = [value];
    while (result.length < len/2) {
        result = result.concat(result);
    }
    return result.concat(result.slice(0, len-result.length));
}

Бонус: если вы хотите заполнить ваш массив строками, это краткий способ сделать это (не так быстро, как concat хоть):

function filledArrayString(len, value) {
    return new Array(len+1).join(value).split('');
}

Стоит отметить, что Array.prototype.fill был добавлен как часть предложения ECMAScript 6 (Гармония). Я предпочел бы использовать полифилл, написанный ниже, прежде чем рассматривать другие варианты, упомянутые в теме.

if (!Array.prototype.fill) {
  Array.prototype.fill = function(value) {

    // Steps 1-2.
    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    // Steps 3-5.
    var len = O.length >>> 0;

    // Steps 6-7.
    var start = arguments[1];
    var relativeStart = start >> 0;

    // Step 8.
    var k = relativeStart < 0 ?
      Math.max(len + relativeStart, 0) :
      Math.min(relativeStart, len);

    // Steps 9-10.
    var end = arguments[2];
    var relativeEnd = end === undefined ?
      len : end >> 0;

    // Step 11.
    var final = relativeEnd < 0 ?
      Math.max(len + relativeEnd, 0) :
      Math.min(relativeEnd, len);

    // Step 12.
    while (k < final) {
      O[k] = value;
      k++;
    }

    // Step 13.
    return O;
  };
}
Другие вопросы по тегам