J'ai observé cela dans Firefox-3.5.7 / Firebug-1.5.3 et Firefox-3.6.16 / Firebug-1.6.2
Quand je lance 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 se passe t-il ici? Est-ce un bug ou est-ce que je comprends mal comment l'utiliser new Array(3)
?
javascript
arrays
map-function
rampion
la source
la source
var y = x.map(function(){return 0; });
, et j'obtiens ceci pour la nouvelle méthode Array () et le littéral de tableau. J'ai testé dans Firefox 4 et Chrome.Réponses:
Il semble que le premier exemple
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, seuls les objets vers lesquels ils pointent.
Comme la carte est exécutée dans le contexte des objets du tableau, je pense que la première carte ne parvient pas du tout à exécuter la fonction tandis que la seconde parvient à s'exécuter.
la source
map
appelle une fonction de rappel fournie une fois pour chaque élément dans un tableau, dans l'ordre, et construit un nouveau tableau à partir des résultats.callback
Est invoqué uniquement pour les index du tableau qui ont des valeurs assignées ; il n'est pas invoqué pour les index qui ont été supprimés ou qui n'ont jamais reçu de valeurs. " Dans ce cas,x
les valeurs de n'ont pas explicitement affecté de valeurs, tandis quey
les valeurs ont été attribuées, même si c'était la valeurundefined
.(new Array(1))[0] === [undefined][0]
.hasOwnProperty
sauf sihasOwnProperty
lui-même a un bug:(new Array(1)).hasOwnProperty(0) === false
et[undefined].hasOwnProperty(0) === true
. En fait, vous pouvez faire exactement la même chose avecin
:0 in [undefined] === true
et0 in new Array(0) === false
.x = new Array(3);
est équivalent àx = [,,,];
, nonx = [undefined, undefined, undefined]
.J'avais une tâche dont je ne connaissais que la longueur du tableau et dont j'avais besoin pour transformer les éléments. Je voulais faire quelque chose comme ça:
Pour créer rapidement un tableau comme celui-ci:
Mais cela n'a pas fonctionné parce que: (voir la réponse de Jonathan Lonowski quelques réponses ci-dessus)
La solution pourrait être de remplir les éléments du tableau avec n'importe quelle valeur (même avec undefined) en utilisant Array.prototype.fill ()
Afficher l'extrait de code
Mettre à jour
Une autre solution pourrait être:
la source
undefined
dans la.fill()
méthode, simplifiant très légèrement le code pourlet arr = new Array(10).fill().map((val,idx) => idx);
Array.from(Array(10))
Avec ES6, vous pouvez le faire
[...Array(10)].map((a, b) => a)
, rapidement et facilement!la source
new Array(10).fill()
. Même résultat que[...Array(10)]
[...Array(10).keys()]
Solution ES6:
Ne fonctionne pas sur le tapuscrit (2.3), cependant
la source
Array(10).fill("").map( ...
est ce qui a fonctionné pour moi avec Typescript 2.9Les 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 deundefined
. Vous pouvez voir la différence en utilisant l'in
opérateur:Cela découle du fait légèrement déroutant que si vous essayez d'obtenir la valeur d'une propriété inexistante d'un objet natif en JavaScript, il renvoie
undefined
(plutôt que de lancer une erreur, comme cela se produit lorsque vous essayez de faire référence à une variable inexistante ), qui est identique à ce que vous obtenez si la propriété a précédemment été explicitement définie surundefined
.la source
Depuis la page MDC pour
map
:[undefined]
applique en fait le setter sur l'index (s) de sorte qu'ilmap
va itérer, tandis quenew Array(1)
juste initialise l'index (es) avec une valeur par défaut deundefined
sorte l'map
ignore.Je pense que c'est la même chose pour toutes les méthodes d'itération .
la source
Dans la spécification ECMAScript 6e édition.
new Array(3)
définissez uniquement la propriétélength
et ne définissez 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 la propriété 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-arrayaccumulationElementList
Étape 5.méthodes
map
,every
,some
,forEach
,slice
,reduce
,reduceRight
,filter
de tableau vérifiera la propriété d'index parHasProperty
méthode interne, doncnew Array(3).map(v => 1)
ne invoquera le rappel.pour plus de détails, voir https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map
Comment réparer?
la source
Je pense que la meilleure façon d'expliquer cela est de regarder la façon dont Chrome le gère.
Donc, ce qui se passe réellement, c'est que new Array () retourne un tableau vide qui a une longueur de 3, mais pas de valeurs. Par conséquent, lorsque vous exécutez
x.map
sur un tableau techniquement vide, il n'y a rien à définir.Firefox «remplit» simplement ces emplacements vides
undefined
même s'il n'a pas de valeurs.Je ne pense pas que ce soit explicitement un bug, juste une mauvaise façon de représenter ce qui se passe. Je suppose que Chrome est "plus correct" car il montre qu'il n'y a en fait rien dans le tableau.
la source
Je suis juste tombé sur ça. Il serait certainement pratique de pouvoir l'utiliser
Array(n).map
.Array(3)
donne à peu près{length: 3}
[undefined, undefined, undefined]
crée les propriétés numérotées:{0: undefined, 1: undefined, 2: undefined, length: 3}
.L'implémentation map () n'agit que sur les propriétés définies.
la source
Pas un bug. C'est ainsi que le constructeur Array est défini pour fonctionner.
De MDC:
La
.map()
méthode inclut uniquement dans les éléments d'itération du tableau auxquels des valeurs ont été explicitement affectées. Même une affectation explicite deundefined
fera qu'une valeur sera considérée comme éligible à l'inclusion dans l'itération. Cela semble étrange, mais c'est essentiellement la différence entre uneundefined
propriété explicite sur un objet et une propriété manquante:L'objet
x
n'a pas de propriété appelée "z", et l'objet eny
possède. Cependant, dans les deux cas, il semble que la "valeur" de la propriété soitundefined
. Dans un tableau, la situation est similaire: la valeur delength
effectue implicitement une affectation de valeur à tous les éléments de zéro àlength - 1
. La.map()
fonction ne fera donc rien (n'appellera pas le rappel) lorsqu'elle est appelée sur un tableau nouvellement construit avec le constructeur Array et un argument numérique.la source
undefined
éternels?x = []
place dex = new Array()
Si vous faites cela afin de remplir facilement un tableau avec des valeurs, ne pouvez pas utiliser fill pour des raisons de support du navigateur et ne voulez vraiment pas faire de boucle for, vous pouvez également le faire
x = new Array(3).join(".").split(".").map(...
ce qui vous donnera un tableau de vide cordes.Assez moche je dois dire, mais au moins le problème et l'intention sont assez clairement communiqués.
la source
Puisque la question est de savoir pourquoi, cela a à voir avec la façon dont JS a été conçu.
Il y a 2 raisons principales auxquelles je peux penser pour expliquer ce comportement:
Performances: étant donné
x = 10000
etnew Array(x)
il est sage pour le constructeur d'éviter de boucler de 0 à 10000 pour remplir le tableau avec desundefined
valeurs.Implicitement «non défini»: Donnez
a = [undefined, undefined]
etb = new Array(2)
,a[1]
etb[1]
reviendront tous les deuxundefined
, maisa[8]
etb[8]
reviendront égalementundefined
même s'ils sont hors de portée.En fin de compte, la notation
empty x 3
est un raccourci pour éviter de définir et d'afficher une longue liste deundefined
valeurs qui sont deundefined
toute façon parce qu'elles ne sont pas déclarées explicitement.Remarque: Étant donné le tableau
a = [0]
eta[9] = 9
,console.log(a)
retournera(10) [0, empty x 8, 9]
, combler automatiquement l'écart en renvoyant la différence entre les deux valeurs déclarées explicitement.la source
Pour des raisons expliquées en détail dans d'autres réponses,
Array(n).map
ne fonctionne pas. Cependant, dans ES2015Array.from
accepte une fonction de carte:la source
Voici une méthode utilitaire simple comme solution de contournement:
Carte simplePour
Exemple complet
Voici un exemple plus complet (avec vérifications d'intégrité) qui permet également de spécifier un index de départ facultatif:
Compte à rebours
La manipulation de l'index transmis au rappel permet de compter à rebours:
la source