Зачем задавать JavaScript-массив?
Firebug представляет (new Array(N))
как массив с N
undefined
в нем. Недавно я столкнулся с сценарием, который показал, что размерный массив со всеми значениями undefined
в нем отличается от нового сконструированного массива размера. Я хотел бы понять разницу.
Предположим, вы хотите сгенерировать список случайных чисел от 0 до 1000.
function kilorange() {
return Math.floor(Math.random() * (1001));
}
no_random_numbers = (new Array(6)).map(kilorange);
my_random_numbers = [undefined, undefined, undefined,
undefined, undefined, undefined].map(kilorange);
Я бы ожидал, что no_random_numbers
и my_random_numbers
будут эквивалентными, но это не так. no_random_numbers
- это еще один массив из undefined
s, тогда как my_random_numbers
- массив с шестью случайными целыми числами. Кроме того, после того, как вы сбросили инструкцию console.count
в kilorange
, я узнал, что моя функция никогда не вызывается для массива, созданного с помощью конструктора Array.
В чем разница и почему map
(и, предположительно, другие итерационные методы) не обрабатывают вышеуказанные массивы одинаково?
Ответы
Ответ 1
стандарт ES (15.4.4.19) определяет алгоритм для map
, и на шаге 8b совершенно ясно, что, поскольку ваш массив фактически не имеет из этих элементов он вернет "пустой" массив длиной 6.
Как отмечали другие, он имеет отношение к объектам массива в js, которые (в отличие от их жестких C-аналогов) очень динамичны и потенциально разрежены (см. 15.4 для алгоритма проверки разреженности).
Ответ 2
При использовании:
var a = new Array(N);
никакие значения не хранятся в новом массиве, и даже индексы "свойства" не создаются. Вот почему map
не будет делать ничего в этом массиве.
Тот факт, что Firebug делает это, является ошибкой/особенностью Firebug. Вы должны помнить, что консоль - это конверт eval
. В консоли Firebug есть другие ошибки/функции.
Например, в консоли Chrome вы увидите приведенный выше массив a
как []
.
Ответ 3
Посмотрите на этот образец и запустите его: http://jsfiddle.net/ArtPD/1/ (он создает два массива без использования map
над ними, а затем список ключ/значения каждого из них)
Я бы сказал, что (new Array(6))
не выделяет свойства "named" (поэтому он не создает "1": undefined, "2": undefined...), а другая форма [undefined, ... ]
делает.
Фактически, если я использую for (var i in ... )
, два выхода:
no_random_numbers
my_random_numbers
0 undefined
1 undefined
2 undefined
3 undefined
4 undefined
5 undefined
Ответ 4
Хороший вопрос, хорошие ответы. Я немного протолкнул прототип map
из MDN. Если он будет таким образом адаптироваться, map
будет работать для new Array([length])
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
var O = Object(this);
var len = O.length >>> 0;
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
if (thisArg) {
T = thisArg;
}
A = new Array(len);
k = 0;
while(k < len) {
var kValue, mappedValue;
if (k in O || (O.length && !O[k])) {
// ^ added this
kValue = O[ k ];
mappedValue = callback.call(T, kValue, k, O);
A[ k ] = mappedValue;
}
k++;
}
return A;
};
На основе ответа Casy Hopes вы также можете сделать mapx
-extension, чтобы иметь возможность использовать map
с некоторыми new Array([length])
:
Array.prototype.mapx = function(callback){
return this.join(',').split(',').map(callback);
}
//usage
var no_random_numbers = new Array(6).mapx(kilorange);
Ответ 5
Чтобы ответить на вопрос заголовка (почему массивы presize), единственное, что я использовал для инициализации массива Array(n)
, - это создать строку длины n-1
:
var x = Array(6).join('-'); // "-----"
Ответ 6
Чтобы ответить на вопрос, почему вы назначили массив, вы сделаете так, чтобы вам не приходилось делать столько индивидуальных распределений. Выделение памяти занимает некоторое время, и это может вызвать запуск сборки мусора, который может занять много времени.
На типичной веб-странице вы не заметите разницы, но если вы делаете что-то важное, это может помочь честно.