JavaScript " new Array (n)" et "Array.prototype.carte" étrangeté

J'ai observé ceci dans Firefox-3.5.7 / Firebug-1.5.3 et Firefox-3.6.16 / Firebug-1.6.2

Quand j'ai le feu jusqu'à 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]

que se passe-t-il? Est-ce un bug, ou est-ce que je ne comprends pas comment utiliser new Array(3) ?

149
demandé sur leaf 2011-03-31 18:37:32

12 réponses

il apparaît que le premier exemple

x = new Array(3);

crée un tableau avec des pointeurs non définis.

et le second crée un tableau avec des pointeurs vers 3 objets non définis, dans ce cas les pointeurs eux-mêmes ne sont pas non définis, seulement les objets qu'ils pointent.

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

comme la carte est exécutée dans le contexte des objets dans le tableau je crois que la première carte ne parvient pas à exécuter la fonction du tout tandis que le second gère exécuter.

95
répondu David Mårtensson 2017-11-22 13:02:38

j'ai eu une tâche que je savais seulement la longueur du tableau et nécessaire pour transformer les éléments. Je voulais faire quelque chose comme ceci:

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

pour créer rapidement un tableau comme celui-ci:

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

mais ça n'a pas marché car: voir la réponse de Jonathan Lonowski quelques réponses plus haut.

Solution pourrait être de remplir les éléments du tableau avec n'importe quelle valeur (même non définie) en utilisant tableau.prototype.remplir()

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

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

mise à Jour

une autre solution pourrait être:

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

console.log(Array.apply(null, Array(10)).map((val, idx) => idx));
70
répondu cstuncsik 2016-10-03 07:23:29

avec ES6, vous pouvez faire [...Array(10)].map((a, b) => a) , rapide et facile!

56
répondu Manuel Beaudru 2016-10-05 16:20:16

Les tableaux sont différents. La différence est que new Array(3) crée un tableau avec une longueur de trois mais aucune propriété, tandis que [undefined, undefined, undefined] crée un tableau avec une longueur de trois et trois propriétés appelées "0", "1" et "2", chacune avec une valeur de undefined . Vous pouvez voir la différence en utilisant l'opérateur in :

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

cela vient du fait un peu confus que si vous essayez d'obtenir la valeur d'une propriété inexistante de n'importe quel natif objet dans JavaScript, il retourne undefined (plutôt que de lancer une erreur, comme cela arrive quand vous essayez de vous référer à une variable inexistante), ce qui est le même que ce que vous obtenez si la propriété a été précédemment explicitement définie à undefined .

14
répondu Tim Down 2011-03-31 15:12:42

de la page du MDC pour map :

[...] callback n'est invoqué que pour les index du tableau qui ont une valeur attribuée; [...]

[undefined] applique en fait le setter sur l'index(es) de sorte que map itérera, tandis que new Array(1) initialise simplement l'index(es) avec une valeur par défaut de undefined de sorte que map le saute.

je crois que c'est la même pour tous itération méthodes .

13
répondu Jonathan Lonowski 2011-03-31 14:47:10

solution ES6:

[...Array(10)]

ne fonctionne pas à la typographie (2.3), bien que

13
répondu Serge Intern 2017-05-05 06:22:51

je pense que la meilleure façon d'expliquer cela est de regarder la façon Chrome poignées.

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

donc ce qui se passe réellement est que new Array() renvoie un tableau vide qui a une longueur de 3, mais aucune valeur. Par conséquent, lorsque vous lancez x.map sur un tableau techniquement vide, il n'y a rien à définir.

Firefox vient de "remplir" ces fentes vides avec undefined même si elle n'a pas de valeurs.

je ne pense pas que cela soit explicitement un bug, juste une mauvaise façon de représenter ce qui se passe. Je suppose que le Chrome est "plus correct" parce qu'il montre qu'il n'y a en fait rien dans le tableau.

7
répondu helloandre 2011-03-31 18:26:00

Dans ECMAScript 6e édition de la spécification.

new Array(3) définit seulement la propriété length et ne définit pas les propriétés d'index comme {length: 3} . voir https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len Étape 9.

[undefined, undefined, undefined] définira les propriétés d'index et les propriétés de longueur comme {0: undefined, 1: undefined, 2: undefined, length: 3} . voir https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList Étape 5.

méthodes map , every , some , forEach , slice , reduce , reduceRight , filter of Array vérifiera la propriété index par HasProperty méthode interne, donc new Array(3).map(v => 1) n'appellera pas le callback.

pour plus de détails, voir https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

comment réparer?

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
répondu wenshin 2017-05-05 06:10:00

vient de tomber sur ça. Il serait certainement pratique de pouvoir utiliser Array(n).map .

Array(3) donne approximativement {length: 3}

[undefined, undefined, undefined] crée les propriétés numérotées:

{0: undefined, 1: undefined, 2: undefined, length: 3} .

la mise en œuvre map() n'agit que sur des propriétés définies.

4
répondu Vezquex 2013-10-29 02:01:55

pas un bug. C'est ainsi que le constructeur de tableaux est défini pour fonctionner.

From MDC:

lorsque vous spécifiez un seul paramètre numérique avec le constructeur du tableau, vous spécifiez la longueur initiale du tableau. Le code suivant crée un tableau de cinq éléments:

var billingMethod = new Array(5);

le comportement du constructeur de tableaux dépend de si le seul paramètre est un nombre.

la méthode .map() inclut seulement dans les éléments d'itération du tableau qui ont explicitement eu des valeurs attribuées. Même une affectation explicite de undefined va provoquer une valeur pour être admissible à l'inclusion dans l'itération. Cela semble étrange, mais c'est essentiellement la différence entre une propriété explicite undefined sur un objet et une propriété manquante:

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

l'objet x n'est pas une propriété appelée "z", et l'objet y ne. Toutefois, dans les deux cas, il apparaît que la "valeur" du bien est undefined . Dans un tableau, la situation est similaire: la valeur de length effectue implicitement une assignation de valeur à tous les éléments de zéro à length - 1 . La fonction .map() ne fera donc rien (n'appellera pas le callback) lorsqu'elle est appelée sur un tableau nouvellement construit avec le constructeur de tableaux et un argument numérique.

3
répondu Pointy 2016-02-18 15:18:03

si vous faites cela afin de remplir facilement un tableau avec des valeurs, ne peut pas utiliser remplir pour des raisons de soutien du navigateur et vraiment ne veulent pas faire une for-boucle, vous pouvez également faire x = new Array(3).join(".").split(".").map(... qui vous donnera un tableau de chaînes vides.

Assez moche je dois dire, mais au moins le problème et l'intention sont assez clairement communiqués.

3
répondu Alex 2016-03-21 14:42:49

dans Chrome , si je fais new Array(3) je reçois [] , donc je pense que vous avez rencontré un bug de navigateur.

-1
répondu stef 2011-03-31 14:43:07