2013-12-02 3 views
16

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

Рассмотрите этот фрагмент кода, который я попробовал в консоли Chrome.

> var N = 10; 
> var x = new Array(N); 
> x 
    [undefined x 10] 

> x.map(function(i) { return 0;}); 
    [undefined x 10] 

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

ответ

22

Если вы хотите, чтобы заполнить массив, вы можете сделать это

Array.apply(null, new Array(5)).map(function() { return 0; }); 
// [ 0, 0, 0, 0, 0 ] 

После некоторого чтения одного из posts linked in the comments, я нашел, что это также может быть записана в виде

Array.apply(null, {length: 5}).map(function() { return 0; }); 

Однако попытки использовать .map по неопределенным значениям не будут работать.

x = new Array(10); 
x.map(function() { console.log("hello"); }); 

// so sad, no "hello" 
// [ , , , , , , , , , ] 

.map пропустит неопределенные значения :(

+3

+1; проблема в том, что 'map' пропускает * индексы *, которым никогда не присваивалось значение. Сравните 'Object.keys (new Array (2))' (без перечислимых свойств) с 'Object.keys ([undefined, undefined])' (два перечислимых свойства, '0' и' 1'). В первом случае массив не имеет значений, назначенных для любых индексов; во втором случае индексам '0' и' 1' присваивается значение 'undefined'. – apsillers

+0

@ папильеры, вы правы. Чтобы уточнить, 'var x = new Array (5);' просто имеет 'x.length == 5' и' Array.prototype'. Помимо этого, перечислимые ключи не задаются. –

+0

очень крутой трюк - я все еще пытаюсь понять, в чем разница между «новым массивом (5)» против «Array.apply (null, new Array (5))» – Raja

1

Функция .map() пропускает записи, которые никогда не были присвоены значениям. Таким образом, на вновь построенном массиве, подобном вашему, он практически ничего не делает.

Here is the MDN description.

1

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

С ECMA script 262, 5.1 specification, раздел 15.4.4.19:

callbackfn вызывается только для элементов массива, который фактически существует ; он не вызывается для отсутствующих элементов массива.

1

Вы можете заполнить массив нулями using this function:

function fillArrayWithNumber(n) { 
    var arr = Array.apply(null, Array(n)); 
    return arr.map(function (x, i) { return 0; }); 
} 

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

Или с небольшим изменением вы можете использовать индексы вместо:

function fillArrayWithIndex(n) { 
    var arr = Array.apply(null, Array(n)); 
    return arr.map(function (x, i) { return i; }); 
} 

fillArrayWithIndex(5); // [0,1,2,3,4] 

Fiddle

2

Вот как это описано в спецификации ECMAScript Language

Вот соответствующая часть Array.prototype.map, как описано (§15.4.4.19)

  • ...
  • .Повторяю, в то время как k < len
    • а) Пусть Pk быть ToString(k).
    • б) Пусть kPresent быть результатом вызова внутреннего метода [[HasProperty]] для O с аргументом Pk.
    • с) Если kPresent является true, то
      • сделать волшебство
  • ...

Поскольку нет initilized элемента в массиве , набрав, например, new Array (1337).hasOwnProperty (42), оценивается в false, поэтому условие на шаге 8.c не выполняется.

Вы можете использовать немного «взломать», чтобы делать то, что хотите.

Array.apply(null, { length: 5 }).map(Number.call, Number) //[0, 1, 2, 3, 4]

Как это работает было thouroughly explained by @Zirak

4

Я просто хотел бы отметить, что теперь вы можете сделать:

Array(2).fill().map(_ => 4); 

Это вернет [4, 4].

+1

'new' и' null' не требуются, это работает с тем же массивом Array (10) .fill(). map (_ => 0) '. +1 в любом случае – CapelliC

+2

или даже короче 'Array (10) .fill (0)' – CapelliC

1

Основываясь на предыдущем ответе, появляется новый более короткий синтаксис. OP хотел создать массив из N элементов инициализированную 0.

var N = 10; 
var x = new Array(N).fill(0); 
// x is now: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] 

Вы также не нужны new - это необязательно в данном контексте.

Проверьте compatibility of your target platform и/или пользуйтесь поломкой, если она недоступна.

Смежные вопросы