¿Por qué el método `mapa` aparentemente no funciona en matrices creadas a través de `nueva matriz (recuento)`?

6 minutos de lectura

avatar de usuario de rampion
Rampion

He observado esto en Firefox-3.5.7/Firebug-1.5.3 y Firefox-3.6.16/Firebug-1.6.2

Cuando enciendo Firebug:

var x = new Array(3)
console.log(x) 
// [undefined, undefined, undefined]

var y = [undefined, undefined, undefined]
console.log(y) 
// [undefined, undefined, undefined]

console.log(x.constructor == y.constructor) // true

console.log( 
  x.map(function() { return 0; })
)
// [undefined, undefined, undefined]

console.log(
  y.map(function() { return 0; })
)
// [0, 0, 0]

¿Que está pasando aqui? ¿Es esto un error, o estoy malinterpretando cómo usar new Array(3)?

  • No obtengo los mismos resultados que ves en la notación literal de la matriz. Sigo sin definir en lugar de 0. Solo obtengo el resultado 0 si configuro algo como var y = x.map(function(){return 0; });, y obtengo esto tanto para el nuevo método Array() como para el literal de matriz. Probé en Firefox 4 y Chrome.

    – Russell Uresti

    31 de marzo de 2011 a las 14:50


  • también roto en Chrome, esto podría definirse en el idioma, aunque no tiene sentido, así que realmente espero que no lo sea

    – Hashbrown

    29 de enero de 2020 a las 0:37

  • cuando usa new Array (4), el resultado no es una matriz con 4 “indefinidos”, obtuvo un resultado diferente: obtuvo “(4) [empty × 4]”

    – yehonatán yehezkel

    31 de mayo de 2022 a las 8:58

avatar de usuario de cstuncsik
cstuncsik

Tenía una tarea en la que solo conocía la longitud de la matriz y necesitaba transformar los elementos. Quería hacer algo como esto:

let arr = new Array(10).map((val,idx) => idx);

Para crear rápidamente una matriz como esta:

[0,1,2,3,4,5,6,7,8,9]

Pero no funcionó porque: (ver la respuesta de Jonathan Lonowski)

La solución podría ser llenar los elementos de la matriz con cualquier valor (incluso sin definir) usando Array.prototype.fill()

let arr = new Array(10).fill(undefined).map((val,idx) => idx);
console.log(new Array(10).fill(undefined).map((val, idx) => idx));

Actualizar

Otra solución podría ser:

let arr = Array.apply(null, Array(10)).map((val, idx) => idx);
console.log(Array.apply(null, Array(10)).map((val, idx) => idx));

  • Vale la pena señalar que no es necesario indicar undefined en el .fill() método, simplificando el código muy ligeramente para let arr = new Array(10).fill().map((val,idx) => idx);

    – Yann Evas

    11 de febrero de 2016 a las 10:39


  • Del mismo modo puedes usar Array.from(Array(10))

    usuario10275798

    15 de julio de 2019 a las 7:47

  • Recomendaría la respuesta de @ eden-landau, ya que es una forma más limpia de inicializar una matriz

    – Sebastián H.

    6 de agosto de 2021 a las 14:41

  • la respuesta es incorrecta

    – Piliponful

    22 de febrero de 2022 a las 11:57

  • Recuerde usar return al mapear a un objeto. :X Array.apply(null, Array(10)).map(() => { return {}; });

    – Trevor Karjanis

    19 mayo 2022 a las 19:18


Avatar de usuario de David Mårtensson
David Martensson

Parece que el primer ejemplo

x = new Array(3);

Crea una matriz con una longitud de 3 pero sin ningún elemento, por lo que los índices [0], [1] y [2] no se crea.

Y el segundo crea una matriz con los 3 objetos indefinidos, en este caso, los índices/propiedades en sí mismos se crean pero los objetos a los que se refieren no están definidos.

y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];

Como el mapa se ejecuta en la lista de índices/propiedades, no en la longitud establecida, si no se crean índices/propiedades, no se ejecutará.

  • De MDC (énfasis mío): “map llama a una función de devolución de llamada proporcionada una vez para cada elemento de una matriz, en orden, y construye una nueva matriz a partir de los resultados. callback se invoca solo para los índices de la matriz que tienen valores asignados; no se invoca para índices que han sido borrados o a los que nunca se les han asignado valores”. En este caso, xLos valores de no tienen valores asignados explícitamente, mientras que yfueron asignados, incluso si era el valor undefined.

    – Martijn

    31 de marzo de 2011 a las 15:03


  • Entonces, ¿es una falla de JavaScript que es imposible verificar si es un puntero indefinido o un puntero a indefinido? Quiero decir (new Array(1))[0] === [undefined][0].

    – Trevor Norris

    7 sep 2012 a las 22:20

  • Bueno, una matriz de indefinidos es diferente de una matriz de punteros a objetos indefinidos. Una matriz de valores indefinidos sería como una matriz de valores nulos, [null, null, null] mientras que una matriz de punteros a undefined sería como [343423, 343424, 343425] apuntando a nulo y nulo y nulo. Las segundas soluciones tienen punteros reales que apuntan a direcciones de memoria, mientras que las primeras no apuntan a ninguna parte. Si eso es una falla de JS, probablemente sea un tema de discusión, pero no aquí;)

    – David Martensson

    17 de septiembre de 2012 a las 16:10

  • @TrevNorris, puedes probar eso fácilmente con hasOwnProperty a menos que hasOwnProperty en sí tiene un error: (new Array(1)).hasOwnProperty(0) === false y [undefined].hasOwnProperty(0) === true. De hecho, puedes hacer exactamente lo mismo con in: 0 in [undefined] === true y 0 in new Array(0) === false.

    – calamar314

    19/03/2015 a las 20:46

  • Hablar de “punteros indefinidos” en JavaScript confunde el problema. El término que estás buscando es “elisiones”. x = new Array(3); es equivalente a x = [,,,];no x = [undefined, undefined, undefined].

    – Matt Kantor

    14 de abril de 2015 a las 2:53

Con ES6, puedes hacer [...Array(10)].map((a, b) => a) ¡Rapido y Facil!

  • Pre-ES6 que puedes usar new Array(10).fill(). Mismo resultado que [...Array(10)]

    – Molomby

    1 de agosto de 2017 a las 2:02


  • Con matrices grandes, la sintaxis extendida crea problemas, por lo que es mejor evitar

    usuario10275798

    15 de julio de 2019 a las 7:42

  • o [...Array(10).keys()]

    – Chungzuwalla

    19 de mayo de 2020 a las 10:06

  • Sé cómo funciona, pero por favor agregue alguna explicaciónpara los que no

    – vsync

    27 oct 2020 a las 18:38


Solución ES6:

[...Array(10)]

Sin embargo, no funciona en mecanografiado (2.3).

Desde la página del MDC para map:

[…] callback se invoca solo para los índices de la matriz que tienen un valor asignado; […]

[undefined] realmente aplica el setter en el(los) índice(s) para que map iterará, mientras que new Array(1) simplemente inicializa los índices con un valor predeterminado de undefined entonces map se lo salta.

Creo que esto es lo mismo para todos. métodos de iteración.

Las matrices son diferentes. la diferencia es que new Array(3) crea una matriz con una longitud de tres pero sin propiedades, mientras que [undefined, undefined, undefined] crea una matriz con una longitud de tres y tres propiedades llamadas “0”, “1” y “2”, cada una con un valor de undefined. Puedes ver la diferencia usando el in operador:

"0" in new Array(3); // false
"0" in [undefined, undefined, undefined]; // true

Esto se debe al hecho ligeramente confuso de que si intenta obtener el valor de una propiedad inexistente de cualquier objeto nativo en JavaScript, devuelve undefined (en lugar de arrojar un error, como sucede cuando intenta hacer referencia a una variable inexistente), que es lo mismo que obtiene si la propiedad se ha establecido explícitamente en undefined.

Por razones explicadas detalladamente en otras respuestas, Array(n).map no funciona Sin embargo, en ES2015 Array.from acepta una función de mapa:

let array1 = Array.from(Array(5), (_, i) => i + 1)
console.log('array1', JSON.stringify(array1)) // 1,2,3,4,5

let array2 = Array.from({length: 5}, (_, i) => (i + 1) * 2)
console.log('array2', JSON.stringify(array2)) // 2,4,6,8,10

  • Esta es la respuesta más limpia para mí.

    – Sebastián H.

    6 de agosto de 2021 a las 14:42

¿Ha sido útil esta solución?