JavaScript "nueva matriz (n)" y " Matriz.prototipo.mapa " rareza


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

Cuando enciendo Firebug:

    >>> x = new Array(3)
    [undefined, undefined, undefined]
    >>> y = [undefined, undefined, undefined]
    [undefined, undefined, undefined]

    >>> x.constructor == y.constructor
    true

    >>> x.map(function(){ return 0; })
    [undefined, undefined, undefined]
    >>> y.map(function(){ return 0; })
    [0, 0, 0]

¿Qué está pasando aquí? ¿Es esto un error, o estoy malinterpretando cómo usar new Array(3)?

Author: leaf, 2011-03-31

12 answers

Parece que el primer ejemplo

x = new Array(3);

Crea una matriz con punteros indefinidos.

Y el segundo crea una matriz con punteros a 3 objetos indefinidos, en este caso los punteros ellos mismos NO son indefinidos, solo los objetos a los que apuntan.

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

Como map se ejecuta en el contexto de los objetos de la matriz, creo que el primer map no puede ejecutar la función mientras que el segundo se las arregla para ejecutarse.

 95
Author: David Mårtensson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-22 13:02:38

Tenía una tarea que solo sabí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 algunas respuestas arriba.

La solución podría ser llenar los elementos de la matriz con cualquier valor (incluso con indefinido) utilizando Array.prototipo.llenar()

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

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

Actualización

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));
 70
Author: cstuncsik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-03 07:23:29

Con ES6, usted puede hacer [...Array(10)].map((a, b) => a), rápido y fácil!

 56
Author: Manuel Beaudru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-05 16:20:16

Los arrays 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 operador in:

"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 lanzar un error, como ocurre cuando se intenta hacer referencia a una variable inexistente), que es lo mismo que lo que se obtiene si la propiedad se ha establecido explícitamente previamente a undefined.

 14
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-31 15:12:42

De la página MDC para map:

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

[undefined] en realidad aplica el setter en el índice(es) para que map itere, mientras que new Array(1) solo inicializa el índice(es) con un valor predeterminado de undefined para que map lo omita.

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

 13
Author: Jonathan Lonowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-31 14:47:10

Solución ES6:

[...Array(10)]

No funciona en typescript (2.3), aunque

 13
Author: Serge Intern,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-05 06:22:51

Creo que la mejor manera de explicar esto es mirar la forma en que Chrome lo maneja.

>>> x = new Array(3)
[]
>>> x.length
3

Así que lo que realmente está sucediendo es que new Array() está devolviendo un array vacío que tiene una longitud de 3, pero sin valores. Por lo tanto, cuando se ejecuta x.map en un técnicamente matriz vacía, no hay nada que establecer.

Firefox solo 'llena' esos espacios vacíos con undefined a pesar de que no tiene valores.

No creo que esto sea explícitamente un error, solo una mala manera de representando lo que está pasando. Supongo que Chrome es" más correcto", ya que muestra que en realidad no hay nada en la matriz.

 7
Author: helloandre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-31 18:26:00

En la especificación de ECMAScript 6th edition.

new Array(3) solo defina la propiedad length y no defina propiedades de índice como {length: 3}. véase https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len Paso 9.

[undefined, undefined, undefined] definirá propiedades de índice y propiedades de longitud como {0: undefined, 1: undefined, 2: undefined, length: 3}. véase https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList Paso 5.

Métodos map, every, some, forEach, slice, reduce, reduceRight, filter of Array comprobará la propiedad index mediante el método interno HasProperty, por lo que new Array(3).map(v => 1) no invocará la devolución de llamada.

Para más detalles, ver https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

¿Cómo arreglar?

let a = new Array(3);
a.join('.').split('.').map(v => 1);

let a = new Array(3);
a.fill(1);

let a = new Array(3);
a.fill(undefined).map(v => 1);

let a = new Array(3);
[...a].map(v => 1);
 5
Author: wenshin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-05 06:10:00

Acabo de encontrarme con esto. Seguramente sería conveniente poder usar Array(n).map.

Array(3) rinde aproximadamente {length: 3}

[undefined, undefined, undefined] crea las propiedades numeradas:
{0: undefined, 1: undefined, 2: undefined, length: 3}.

La implementación de map() solo actúa sobre propiedades definidas.

 4
Author: Vezquex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-29 02:01:55

No es un error. Así es como se define el constructor de matriz para trabajar.

De MDC:

Cuando se especifica un único parámetro numérico con el constructor de matriz, se especifica la longitud inicial de la matriz. El siguiente código crea una matriz de cinco elementos:

var billingMethod = new Array(5);

El comportamiento del constructor de matriz depende de si el parámetro único es un número.

El método .map() solo incluye en la iteración elementos de la matriz a la que se han asignado valores explícitamente. Incluso una asignación explícita de undefined hará que un valor se considere elegible para su inclusión en la iteración. Eso parece extraño, pero es esencialmente la diferencia entre una propiedad explícita undefined en un objeto y una propiedad faltante:

var x = { }, y = { z: undefined };
if (x.z === y.z) // true

El objeto x no tiene una propiedad llamada "z", y el objeto y hace. Sin embargo, en ambos casos parece que el "valor" de la propiedad es undefined. En una matriz, la situación es similar: el valor de length realiza implícitamente una asignación de valor a todos los elementos desde cero hasta length - 1. Por lo tanto, la función .map() no hará nada (no llamará a la devolución de llamada) cuando se llame a una matriz recién construida con el constructor de matriz y un argumento numérico.

 3
Author: Pointy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-18 15:18:03

Si está haciendo esto para llenar fácilmente una matriz con valores, no puede usar fill por razones de soporte del navegador y realmente no desea hacer un bucle for, también puede hacer x = new Array(3).join(".").split(".").map(... que le dará una matriz de cadenas vacías.

Bastante feo tengo que decir, pero al menos el problema y la intención se comunican con bastante claridad.

 3
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-21 14:42:49

En Chrome, si lo hago new Array(3) obtengo [], así que mi conjetura es que te has encontrado con un error en el navegador.

 -1
Author: stef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-31 14:43:07