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)
?
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.
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));
avec ES6, vous pouvez faire [...Array(10)].map((a, b) => a)
, rapide et facile!
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
.
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 .
solution ES6:
[...Array(10)]
ne fonctionne pas à la typographie (2.3), bien que
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.
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);
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.
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.
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.
dans Chrome , si je fais new Array(3)
je reçois []
, donc je pense que vous avez rencontré un bug de navigateur.