@psychadelic
Tu as gagné : tu as les plus grosses...
(attention à ne pas marcher dessus...)
@psychadelic
Tu as gagné : tu as les plus grosses...
(attention à ne pas marcher dessus...)
Bonjour,Ecoutez la voix de la sagesseEnvoyé par danielhagnoul
les tableaux associatifs sont une vue de l'esprit et n'existe pas en javascript comme c'est le cas en PHP.Envoyé par Beginner.
Non c'est n'importe quoi, en javascript tout est objet donc on a des « Array Objects » et des « Object Objects » et ce depuis le début comme le montre cette édition de Standard ECMA-262 de June 1997.Envoyé par psychadelic
Souvent l'ambiguïté vient de l'écriture qui pour un « Object Objects » peut être obj.propriete ou obj[propriete].
La propriété length n'existe pas pour les « Object Objects » contrairement au « Array Objects ».
Avec « Array Objects » :
avec « Object Objects » :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 var tab = [ 'zero', 'un', 'deux']; // pour y accéder il faut une écriture du type alert(tab[0]) // >> zero // dans ce cas la propriété length existe alert(tab.length) // >> 3
Il existe quand même des choses surprenantes lorsque l'on fait du mixage (fortement déconseillé)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 var obj = { 0: 'zero', 1: 'un', 2: 'deux'}; // pour y accéder on peut utiliser une écriture du type, entre autres alert(obj[0]) // >> zero // dans ce cas la propriété length, n'existe pas. alert(obj.length) // >> undefined
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 var arr = [ 'zero', 'un', 'deux']; alert(arr.length) // >> 3 // ajout d'un élément arr['trois'] = 'trois'; alert(arr['trois']) // >> trois alert(arr.length) // >> 3 et non 4 alert(JSON.stringify(arr)); // >> surprise
Alors là c'est marrant on peut affecter une valeur à length :
Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 var tbl2 = new Array(3); tbl2[0] = "Doe"; tbl2[1] = "zim"; tbl2[2] = "quatre cinq"; tbl2[100] = "100"; console.log("type de tbl2: ", typeof tbl2, Array.isArray(tbl2), "taille: ", tbl2.length, " - ", Object.keys(tbl2).length); tbl2.length = 10; console.log("type de tbl2: ", typeof tbl2, Array.isArray(tbl2), "taille: ", tbl2.length, " - ", Object.keys(tbl2).length); tbl2.length = 300; console.log("type de tbl2: ", typeof tbl2, Array.isArray(tbl2), "taille: ", tbl2.length, " - ", Object.keys(tbl2).length);
Résultat :
Bref on peut lui affecter ce qu'on veut... c'est n'importe quoi !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 type de tbl2: object true taille: 101 - 4 type de tbl2: object true taille: 10 - 3 type de tbl2: object true taille: 300 - 3
---> Cela permet de supprimer des éléments comme on peut le voir mais pas d'en ajouter...
Pour votre bon plaisir, j’ai épluché la spec
Dans la version 2017, c’est à la section 9.4.2 :
Ça dit de manière plus détaillée ce qui est dit dans le lien MDN que jreaux62 a donné.Envoyé par la spec
Concrètement, ça veut dire en gros deux choses.Envoyé par traduction
Primo, on peut avoir un tableau contenant un seul élément à l’index 9000, la longueur du tableau sera 9001.
Secundo, s’il nous vient l’idée saugrenue de modifiier la propriété length (perso j’ai longtemps cru qu’elle était en lecture seule), ça tronque le tableau, ce qui peut être source de calvitie précoce si on n’est pas prévenu.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 var tableau = []; tableau[9000] = "bidule"; console.log(tableau.length); // 9001
On voit aussi ressortir l’idée que les propriétés qui ne sont pas des index ne sont pas prises en compte. C’est précisé dans le paragraphe qui vient juste après dans la spec :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 var tableau = [ "a", "b", "c", "d", "e", "f" ]; tableau.length = 3; console.log(tableau); // [ "a", "b", "c" ]
Envoyé par la spec
(La notion d’« index » est définie à la section 6.1.7, c’est une chaîne numérique dont la valeur doit être comprise entre 0 et 232 - 1.)Envoyé par traduction
Plus clairement, ça veut dire que si on utilise autre chose qu’un nombre (ou une chaîne à valeur numérique) comme index, le tableau va avoir le même comportement qu’un objet de base, et temporairement « oublier » qu’il est un tableau.
En fait, si on peut affecter des clés non numériques à un tableau en JavaScript, c’est seulement dû au fait qu’il hérite de Object, c’est purement accidentel. C’est trompeur par rapport à l’autre langage de script du Web historiquement célèbre, PHP, qui gère des tableaux dits associatifs. En JS, on se fait avoir car on s’attend à ce qu’il y ait de la magie là où il n’y en a pas.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 var objetDeBase = {}; objetDeBase[9000] = "bidule"; objetDeBase["reponse"] = 42; console.log(objetDeBase); // Object { 9000: "bidule", reponse: 42 }
Ce comportement d’objet de base explique aussi ce qui se passe avec les index négatifs. Comme expliqué dans la doc de Array, la notation crochet n’est pas inhérente aux tableaux, c’est une façon d’accéder à une propriété d’objet qui ne collerait pas avec la syntaxe de JS autrement. En réalité, l’expression entre les crochets est d’abord convertie en chaîne.
C’est d’ailleurs ce que dit la spec quand elle parle de nom de propriété. Ça veut dire qu’en fait, on passe un nombre, qui est d’abord converti en chaîne, puis re-converti en nombre…Encore une fois, un bidouillage de conception qui fait que JS ressemble à C mais que c’est seulement une apparence.
Bref, tout ça pour dire que si on passe l’index -5, il est en réalité traité comme la chaîne "-5", et comme il ne répond pas au critère « entier non négatif », il n’est pas géré de façon spéciale par le tableau.
À propos des emplacements vides, je n’ai pas réussi à trouver où ça parle de ça dans la spec, mais je peux parler de ma propre expérience. Pour des raisons de performance, les implémentations peuvent choisir de représenter un tableau de manière « creuse » s’il a une grande taille mais contient en réalité peu d’éléments. Ça évite de faire de grosses allocations de mémoire. Par exemple :
Comme tu l’as vu, pierrot10, la console affiche des « empty slots » qui indiquent les éléments non initialisés. C’est différent de undefined, et je trouve que cette différence est souvent mal documentée, peut-être parce qu’avant ECMAScript 5 et les nouvelles méthodes de parcours de tableaux (map, forEach, etc.), elle n’avait aucun impact sur le comportement des scripts.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 var tableau = []; tableau[1] = "bidule"; tableau[9000] = "machin"; console.log(tableau.length); // 9001 console.log(tableau); // Array [ <1 empty slot>, "bidule", <8 empty slots>, ]
Si on itère sur un tableau « creux » de manière traditionnelle avec une bonne vieille boucle for :
Évidemment, tous les index seront parcourus car c’est nous qui gérons la variable i.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 for (let i = 0; i < tableau.length; i++) { console.log(tableau[i]); }
La douteuse for..in itère sur les propriétés énumérables d’un objet — et j’insiste sur objet, elle n’est pas censée être utilisée pour parcourir un tableau. Mais par chance, les valeurs qu’on attribue à un tableau, quand on le fait de façon habituelle, sont énumérables ; et les emplacements vides ne le sont pas.
Notez que les index, cette fois, sont restés sous forme de chaînes.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 for (let prop in tableau) { console.log(prop, tableau[prop]); } // "1" "bidule" // "9000" "machin"
On le sait, for..in n’est pas fiable car elle prend aussi en compte les propriétés rajoutées dans la chaîne de prototypes. Si un script tiers étend le prototype de Array ou Object sans y prendre garde, on va se retrouver avec des propriétés parasites un peu partout et ça peut, encore une fois, faire prospérer le commerce des lotions capillaires. C’est pour cette raison que Protoype.js est mort et que jQuery vit toujours
Doksuri a mentionné la méthode Object.keys, c’est une alternative fiable à for..in : elle renvoie une liste des propriétés propres, c’est-à-dire les propriétés que l’objet possède lui-même et qui ne viennent pas du prototype. Cette liste est de type Array, elle a donc une propriété length, qui donne le nombre réel de propriétés de l’objet.
La plus récente boucle for..of, pour une raison que je n’ai pas précisément comprise (peut-être parce qu’elle est faite pour les objets itérables de manière générale, et pas seulement les tableaux), parcourt les emplacements vides. Donc attention si le tableau a une grande longueur, ça peut geler le script.
C’est là qu’on voit que les emplacements vides sont en quelques sortes « convertis » en undefined quand ils sont pris en compte, ce qui est, quand on y pense, parfaitement logique.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 for (let item of tableau) { console.log(item); } // undefined // "bidule" // undefined // ... // ... // ... // Error: Script terminated by timeout
Et enfin il y a les méthodes ES5 qui ne tiennent pas compte des emplacements vides, ce qui permet une plus grande efficacité avec les tableaux creux :
Pour le cas de Array.from, j’ai l’intuition que c’est un peu la même chose que for..of : c’est fait pour tous les objets itérables, pas seulement les tableaux, donc ça tient compte des emplacements vides. C’est une technique pratique pour « gonfler » un tableau creux, mais du coup, attention à la taille du tableau.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 tableau.forEach(function (item, index) { console.log(index, item); }); // 1 "bidule" // 9000 "machin"
Pour l’anecdote, j’ai testé tableau.join("-") et ça m’a renvoyé une chaîne de longueur supérieure à 9000 (over nine thousands, je suis sûr que vous l’attendiez tous
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 Array.from(tableau).forEach(function (item, index) { console.log(index, item); }); // 0 undefined // 1 "bidule" // 2 undefined // ... // ... // ... // Error: Script terminated by timeout) sans broncher plus que ça. Donc j’imagine que les chaînes coûtent moins cher en performances que les tableaux, même si je ne sais pas ce qui se passe sous le capot pendant la conversion.
Encore une petite remarque à propos des emplacements vides : on peut en créer facilement lorsqu’on initialise un tableau avec ses éléments en une seule instruction, en ajoutant des virgules.
Ça permet entre autres de sauter l’indice zéro et d’avoir un tableau qui « fait semblant » de commencer à 1.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 var fruits = [ , "pomme", "coing", , "rhubarbe" ]; console.log(fruits);
Attention cependant, il y a un piège : la dernière virgule n’est pas prise en compte, pour des raisons de permissivité de la syntaxe. Cette permissivité est bienvenue quand on déclare de grands tableaux sur plusieurs lignes, typiquement des tableaux d’options dans des fichiers de configuration. Malheureusement la syntaxe de JSON, qui se veut plus stricte, ne permet pas ça (ça s’applique aussi aux objets littéraux), ce qui mène à des erreurs fréquentes lorsqu’on veut insérer ou réordonner des lignes. C’était mon petit coup de gueule
Au final, pierrot10, je n’ai pas de réponse exacte à ta question. Les tableaux commencent à zéro en JS, on ne peut pas y faire grand chose, mais tu es libre d’utiliser les index que tu veux tant que tu sais ce que tu fais![]()
Bon après réflexion c'est plus ou moins dans la logique du reste de ce qui a été dit car au final après affectation de length on se retrouve avec le bon chiffre ensuite puisque si on lui affecte un nombre plus petit que sa valeur précédente tous les éléments qui dépassent sont supprimés et si on lui affecte un nombre plus grand ben c'est comme d'hab je suppose qu'on aura des "trous"...
Une question : est-ce un bon moyen de supprimer des éléments d'un tableau ?
c'est parce que sous JavaScript le concept de tableau est différente ce que l'on rencontre habituellement dans d'autres langages informatiques.
Ce sont avant tout des objets, mais on peut aussi les manipuler de manière similaire aux tableaux classiques.
Si l'on veut les manipuler comme des tableaux classiques, cad avec des indices numériques,
cela implique certaines règles, comme par exemple celles du premier indice possible commençant à zéro,
et les indices doivent être positifs, etc..
Libre ensuite au programmeur de manipuler les objets javascripts comme des tableaux "classique" ou non.
D'un autre coté on imagine mal qu'un langage informatique fasse l'impasse sur la manipulation des "tableaux classiques", car cela correspondrai à faire une croix sur pas mal de fonctionnalités algorithmiques.
Pour mieux m'expliquer voici un bout de code:resultat :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 var jso_liste = {'2':'deux', 'k5':'cinq', 8:'huit'} ; jso_liste['8'] = 'nv-8'; jso_liste[2] = 'nv-2'; jso_liste['k5'] = 'nv-5'; for (var item in jso_liste ) { console.log( item + '--> ' + jso_liste[item]); }
JavaScript utilise indifféremment une clé sous format string ou numérique ( ici 8 ou '2' )2--> nv-2
8--> nv-8
k5--> nv-5
Ah ben merci Watilin ! Je vois qu'il y a des éléments intéressants par rapport à ma question !
Ah oui ça aussi c'est un truc qui m'avais interpellé, un moment je croyais que la notation avec les guillemets ou les apostrophes c'était pour json...
Mais par la suite il me semble avoir vu qu'en fait, notées avec ou sans les guillemets ou les apostrophes, les clés sont de type string.
De rien à vous deux
Un truc que j’ai oublié de dire : quand on fait ça
c’est exactement équivalent à
Code : Sélectionner tout - Visualiser dans une fenêtre à part var arr = new Array(1000);
Donc il est courant, en fait, d’utiliser length en écriture, sans forcément s’en rendre compte.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 var arr = new Array(); arr.length = 1000;
En l’occurence, le tableau sera initialisé avec 1000 emplacements vides. Ça m’a causé quelques pertes de cheveux par le passé quand j’essayais d’obtenir rapidement la liste des n premiers entiers naturels :
Ça ne m’affichait rien du tout, parce que forEach ignore superbement les emplacements vides. Maintenant je sais qu’il faut faire comme ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part new Array(n).forEach((nothing, index) => { console.log(index); })
Bien sûr, ce serait bien moins gourmand en mémoire et plus élégant avec une fonction génératrice…
Code : Sélectionner tout - Visualiser dans une fenêtre à part Array.from(new Array(n)).forEach((nothing, index) => { console.log(index); })![]()
il m'est arrivé d'utiliser des Tbl.length = 0; pour remettre un tableau "à zéro" sachant que derrière j'utilisais a uniquement des Tbl.push(); pour le remplir suivant les besoins...
Utiliser des tableaux en JavaScript demande pas mal de rigueur, et il vaut mieux éviter de faire n'importe quoi, comme par exemple :
parce que cela peut très vite devenir un code ingérable
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 function Prima (arg) { console.log('Prima => '+ arg); } function Dona (arg) { console.log('Dona => '+ arg); } var jso_tbl = []; jso_tbl[0] = 'toto'; jso_tbl[1] = function (arg) { console.log('salut '+ arg)}; jso_tbl[2] = Prima; jso_tbl[1](jso_tbl[0]); // => salut toto //.... jso_tbl[2]('premier délire'); jso_tbl[2] = Dona; jso_tbl[2]('second délire');
Bon j'en profite pour poser (à tous même si je cite Watilin) une question peut-être difficile que je me posais,
Coté mémoire c'est mieux mais saurais-tu ce qu'il en est coté rapidité ?
Je me demande si l’interpréteur JS ne va pas traiter ce type de tableau comme des objets avec des clés|valeurs et du coup ce serait plus lent ???
Je me pose cette question par exemple pour une fonction mathématique dont on n'a pas de formule formelle genre comme sin(x), cos(x), log(x)... mais on a juste une liste de correspondance x|y sauf que x peut faire de grand bon exemple ;
x:1 --> y:7
x:5 --> y:43
x:3000 --> y:157
...
Pour fabriquer cette fonction, quel serait le mieux, utiliser un tableau avec des vides ou un objet ?
Sachant qu'on doit pouvoir savoir si pour un x donné il n'y a pas de y correspondant, par exemple f[3] reverrait undefined ou null ou je ne sais pas quoi et bien sûr par exemple f[3000] reverrait 157.
Je ne sais pas si je suis clair.
@ Beginner
Est-ce que le langage JavaScript est taillé pour ce type de problématique ?
Peut-être pas mais le petit projet est en JS donc il me faut faire une fonction de conversion en JS...
Je pourrais dire c'est quoi plus précisément mais c'est peut-être difficile à faire comprendre quand on a pas la tête plongée dans le problème et on sortirait du sujet du fil, le moment voulu j'ouvrirai peut-être un autre fil...
Je ne sais pas ou un autre fil puisse exister, mais mes derniers "travaux" m'ont amené à me replonger dans cet univers si particulier des Tableaux en Javascript.
Je vous livre "en brut" mes découvertes:
Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 var tt = ['aa','bb','cc','dd']; // length = 4; et les indices vont de zéro à 3... delete tt[2]; // oui, on peut le faire! et cela est différent d'un tt.splice(2, 1); for (let elm of tt) { console.log(elm); // => 'aa' , 'bb', undefined , 'dd' } // vérifications : console.log( 2 in tt); // => false console.log( 3 in tt); // => true console.log ( tt.includes('cc') ); // => false console.log ( tt.includes('aa') ); // => true
mes 2 cents![]()
Avec le length ...
du coup c'est une sorte de slice ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 tab=[1,2,3,5,6,7] tab.length=2 alert (tab[1])
pour moi,ce serait plutôt une pratique de codage hasardeuse.
Je ne pourrais pas écrire ce genre de code sans mettre un commentaire pour en expliquer la raison.
et sinon, non, ce n'est pas l'équivalent d'un slice, mais d'un splice :
écrire tab.length=2; est ici équivalent à tab.splice(2,9999);
Pour bien comprendre ce qui se passe ici, il faut noter plusieurs choses.
1. delete agit sur des propriétés d’objets. On en a déjà parlé dans ce fil, les tableaux sont aussi des objets, un peu par hasard. C’est parce que Array hérite de Object. (Hériter au sens d’un langage à prototypes, hein, mais on ne va pas rentrer dans les détails.)
En réalité, le delete de JavaScript est un truc compliqué, il y a plein de détails savoureux dans la doc.
2. Un tableau duquel on a supprimé une propriété affichera un emplacement vide.
Code console : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 exemple = [ "Lea", "Emilie", "Tronny", "Apollo" ] delete exemple[2] // true exemple // Array(4) [ "Lea", "Emilie", <1 empty slot>, "Apollo" ]
3. La boucle for of « transforme » les emplacements vides en undefined. Ce n’est pas le cas avec les méthodes d’itération comme forEach.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 exemple.forEach(function (item, index) { console.log(item, index); }); // Lea 0 // Emilie 1 // Apollo 3
En effet, on peut voir ça comme un slice qui commencerait toujours à 0. C’est le comportement défini par la spec, j’en avais déjà parlé mais ça fait 7 mois alors je vous remets le passage ici
Pour les curieux et les curieuses, j’ai sorti ça de la version HTML de la spec 2018 (le passage qui nous intéresse n’a pas changé par rapport à 2017). Attention avant de cliquer, la page est lourde : https://www.ecma-international.org/e...exotic-objectsEnvoyé par ECMA-262 edition 9
Je vous mets aussi le lien vers la version pdf : https://www.ecma-international.org/p...T/Ecma-262.pdf
Et si le tableau a une longueur supérieure à 9999 ?
Ta remarque m’a poussé à chercher l’origine du nom “splice” et c’est amusant, le mot existe dans la langue anglaise (je croyais que c’était juste une déformation de “slice”).
“Slice” signifie trancher (slice of bread, tranche de pain), alors que “splice” signifie coller, épisser (oui, avec deux « s », l’épissure c’est une sorte de tressage qu’on fait entre deux morceaux de corde pour les lier ensemble).
Personnellement, l’analogie du montage cinéma me parle davantage. Quand on utilise splice, en général, c’est pour recoller deux bouts d’un tableau après qu’on en a retiré un morceau :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 let tableau = [ "a", "b", "c", "d" ]; tableau.splice(2, 1); // renvoie [ "c" ], un nouveau tableau // le tableau dorigine a été recollé console.log(tableau); // [ "a", "b", "d" ]
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager