Почему Array.apply(null, [args]) действует непоследовательно при работе с разреженными массивами?
Недавно я обнаружил следующий фрагмент кода на SO, чтобы помочь быстро заполнить массив значениями по умолчанию:
Array.apply(null, new Array(3)).map(function() {return 0;});
Учитывая поведение конструктора Array и метода apply, приведенный выше фрагмент можно также переписать как таковой:
Array.apply(null, [undefined, undefined, undefined]).map(function() {return 0;});
Этот метод также полезен при работе с разреженными массивами, которые вы хотите заполнить значениями по умолчанию:
var sparseArr = [3,,,4,1,,],
denseArr = Array.apply(null, sparseArr).map(function(e) {
return e === undefined ? 0 : e;
});
// denseArr = [3,0,0,4,1,0]
Однако в этом случае возникают две странности:
- Если конечный член
sparseArr
равен undefined, этот термин не отображается в denseArr
- Если
sparseArr
содержит только один член (например, sparseArr = [1]
) или один термин, за которым следует один конечный член undefined (например, sparseArr = [1,]
), итоговый denseArr
равен [undefined x 1]
Может ли кто-нибудь объяснить это поведение?
Ответы
Ответ 1
new Array(3)
[...] также можно переписать как [undefined, undefined, undefined]
Нет - как вы только что видели, конструктор массива создает разреженные массивы, поэтому его следует переписать как [,,,]
.
Если конечный член sparseArr равен undefined
Неа. Вы забываете о конечных комматиках, которые являются необязательными с EcmaScript 5. Фактически [1]
просто эквивалентен [1,]
(обе имеют длину 1
).
Чтобы получить разреженные "слоты", вам нужно будет добавить дополнительные запятые:
[] // empty array
[,] // empty array
[,,] // [undefined x 1]
[,,,] // [undefined x 2]
Если sparseArr
содержит только один член, результирующий denseArr
равен [undefined x N]
Подумайте, что значит называть метод apply
:
Array.apply(null, [3,,4,1]) ≡ Array(3, undefined, 4, 1)
Array.apply(null, [3,4]) ≡ Array(3, 4)
Array.apply(null, [1]) ≡ Array(1)
И вы знаете, что делает Array
конструктор при вызове с помощью одного числового аргумента - он создает разреженный массив этой длины...
Ответ 2
С ECMA 262 вы можете иметь конечную запятую в массивах. Ее присутствие никак не изменяет содержимое массива.
Если у вас есть две или несколько последовательных запятых без запятой внутри массива, их содержимое устанавливается как undefined.
Примечание: поскольку undefined
в массивах имеет нестандартное поведение в IE и 9, я бы не использовал его там. Вместо этого используйте null
.
Тот факт, что у вас есть удивительные результаты, когда sparseArr содержит один элемент, состоит в том, что у Array есть два разных конструктора: если вы передаете ему несколько аргументов, он создает массив с этой последовательностью, если вы передаете ему одиночное число, он создает массив длины "число", заполненное undefined.
new Array(1, 2, 3)
=> [1, 2, 3]
new Array(2)
=> [undefined, undefined]