La plupart des tutoriels que j'ai lus sur des tableaux en JavaScript (y compris w3schools et devgur ) suggèrent que vous pouvez initialiser un tableau avec une certaine longueur en transmettant un entier à la Constructeur de tableau utilisant la syntaxe var test = new Array(4);
.
Après avoir utilisé cette syntaxe de manière généralisée dans mes fichiers js, j'ai exécuté l'un des fichiers via jsLint , et cela a flippé:
Erreur: Problème à la ligne 1, caractère 22: attendu ')' et à la place vu '4'.
var test = new Array (4);
Problème à la ligne 1, caractère 23: attendu ';' et a plutôt vu ')'.
var test = new Array (4);
Problème à la ligne 1, caractère 23: Identifiant attendu et à la place, vu ')'.
Après avoir lu l'explication de jsLint sur son comportement , il semble que jsLint n'aime pas vraiment la syntaxe new Array()
, mais préfère plutôt []
lors de la déclaration de tableaux.
J'ai donc quelques questions. D'abord, pourquoi? Est-ce que je prends des risques en utilisant plutôt la syntaxe new Array()
? Existe-t-il des incompatibilités de navigateur dont je devrais être au courant? Et deuxièmement, si je passe à la syntaxe des crochets, existe-t-il un moyen de déclarer un tableau et de définir sa longueur sur une seule ligne, ou dois-je faire quelque chose comme ça:
var test = [];
test.length = 4;
Pourquoi voulez-vous initialiser la longueur? Théoriquement, cela n'est pas nécessaire. Cela peut même entraîner un comportement déroutant, car tous les tests utilisant la variable length
pour savoir si un tableau est vide ou non indiqueront que le tableau n'est pas vide.
Certainstests montrent que la définition de la longueur initiale de grands tableaux peut être plus efficace si le tableau est remplies par la suite, mais le gain de performance (le cas échéant) semble différer d’un navigateur à l’autre.
jsLint n'aime pas new Array()
parce que le constructeur est ambigu.
new Array(4);
crée un tableau vide de longueur 4. Mais
new Array('4');
crée un tableau contenant la valeur '4'
.
Concernant votre commentaire: Dans JS, vous n'avez pas besoin d'initialiser la longueur du tableau. Ça pousse dynamiquement. Vous pouvez simplement stocker la longueur dans une variable, par exemple.
var data = [];
var length = 5; // user defined length
for(var i = 0; i < length; i++) {
data.Push(createSomeObject());
}
Array(5)
vous donne un tableau de longueur 5 mais pas de valeur, vous ne pouvez donc pas le parcourir.
Array.apply(null, Array(5)).map(function () {})
vous donne un tableau de longueur 5 et non défini comme valeur, il peut maintenant être itéré.
Array.apply(null, Array(5)).map(function (x, i) { return i; })
vous donne un tableau de longueur 5 et de valeurs 0,1,2,3,4.
Array(5).forEach(alert)
ne fait rien, Array.apply(null, Array(5)).forEach(alert)
vous donne 5 alertes
ES6
nous donne Array.from
pour que vous puissiez maintenant utiliser aussi Array.from(Array(5)).forEach(alert)
Si vous voulez initialiser avec une certaine valeur, il est bon de le savoir ...Array.from('abcde')
, Array.from('x'.repeat(5))
or Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]
Avec ES2015 .fill()
vous pouvez maintenant faire simplement:
// `n` is the size you want to initialize your array
// `0` is what the array will be filled with (can be any other value)
Array(n).fill(0)
Ce qui est beaucoup plus concis que Array.apply(0, new Array(n)).map(i => value)
Il est possible de supprimer le 0
dans .fill()
et de l'exécuter sans argument, ce qui remplira le tableau avec undefined
. ( Cependant, cela échouera dans TypeScript )
Le plus court:
[...Array(1000)]
[...Array(6)].map(x=>0);
// [0, 0, 0, 0, 0, 0]
OU
Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]
Remarque: vous ne pouvez pas mettre en boucle les logements vides Array(4).forEach( (_,i) => {} )
OU
Array(6).fill(null).map( (x,i) => i );
// [0, 1, 2, 3, 4, 5]
( TypeScript safe )
Lors de la création d'un tableau 2D avec fill
intuitivement, il convient de créer de nouvelles instances. Mais ce qui va réellement se passer, c'est que le même tableau sera stocké en tant que référence.
var a = Array(3).fill([6]);
// [[6], [6], [6]]
a[ 0 ].Push( 9 );
// [[6,9], [6,9], [6,9]]
Solution
var a = [...Array(3)].map(x=>[]);
a[ 0 ].Push( 4, 2 );
// [[4,2], [ ], [ ]]
Ainsi, un tableau 3x2 ressemblera à ceci:
[...Array(3)].map(x=>Array(2).fill(0));
// [ [0,0] ,
// [0,0] ,
// [0,0] ]
var Chessboard = [...Array( 8 )].map( (x,j) =>
Array( 8 ).fill( null ).map( (y,i) =>
`${ String.fromCharCode( 65 + i ) }${ 8 - j }`));
// [ [ A8,B8,C8,D8,E8,F8,G8,H8 ],
// [ A7,B7,C7,D7,E7,F7,G7,H7 ],
// [ A6,B6,C6,D6,E6,F6,G6,H6 ],
// [ A5,B5,C5,D5,E5,F5,G5,H5 ],
// [ A4,B4,C4,D4,E4,F4,G4,H4 ],
// [ A3,B3,C3,D3,E3,F3,G3,H3 ],
// [ A2,B2,C2,D2,E2,F2,G2,H2 ],
// [ A1,B1,C1,D1,E1,F1,G1,H1 ] ]
ES6 introduit Array.from
qui vous permet de créer un Array
à partir de n’importe quel "semblable à un tableau" ou iterables objets:
_Array.from({length: 10}, (x, i) => i);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_
Dans ce cas, _{length: 10}
_ représente la définition minimale d'un objet "semblable à un tableau" : un objet vide avec juste un length
propriété définie.
Array.from
permet à un deuxième argument d'être mappé sur le tableau résultant.
Cela initialisera la propriété length à 4:
var x = [,,,,];
Je suis surpris qu'il n'y ait pas eu de solution fonctionnelle suggérée vous permettant de définir la longueur sur une seule ligne. Ce qui suit est basé sur UnderscoreJS:
var test = _.map(_.range(4), function () { return undefined; });
console.log(test.length);
Pour les raisons mentionnées ci-dessus, je ne le ferais que si je voulais initialiser le tableau avec une valeur spécifique. Il est intéressant de noter que d'autres bibliothèques implémentent la gamme, notamment Lo-dash et Lazy, qui peuvent présenter des caractéristiques de performances différentes.
(c'était probablement mieux comme commentaire, mais c'est devenu trop long)
Donc, après avoir lu ceci, j'étais curieux de savoir si la pré-allocation était réellement plus rapide, car en théorie cela devrait être. Cependant, ce blog a donné quelques conseils contre elle http://www.html5rocks.com/en/tutorials/speed/v8/ .
Donc, toujours incertain, je l'ai mis à l'épreuve. Et comme il s'avère que cela semble en fait être plus lent.
var time = Date.now();
var temp = [];
for(var i=0;i<100000;i++){
temp[i]=i;
}
console.log(Date.now()-time);
var time = Date.now();
var temp2 = new Array(100000);
for(var i=0;i<100000;i++){
temp2[i] = i;
}
console.log(Date.now()-time);
Ce code donne les résultats suivants après quelques exécutions occasionnelles:
$ node main.js
9
16
$ node main.js
8
14
$ node main.js
7
20
$ node main.js
9
14
$ node main.js
9
19
S'il vous plaît, les gens n'abandonnent pas vos anciennes habitudes pour l'instant. Il y a une grande différence de vitesse entre allouer une fois la mémoire puis utiliser les entrées de ce tableau (comme auparavant) et l'allouer plusieurs fois à mesure que le tableau s'agrandit (ce qui est inévitablement ce que le système fait sous le capot avec d'autres méthodes suggérées) .
Bien sûr, rien de tout cela n’a d’importance à moins de vouloir faire quelque chose de cool avec des baies plus grandes. Alors ça le fait.
Comme il semble toujours n'y avoir aucune option dans JS pour le moment pour définir la capacité initiale d'un tableau, j'utilise ce qui suit ...
var newArrayWithSize = function(size) {
this.standard = this.standard||[];
for (var add = size-this.standard.length; add>0; add--) {
this.standard.Push(undefined);// or whatever
}
return this.standard.slice(0,size);
}
Il y a des compromis impliqués:
standard
réserve en permanence autant d’espace que le tableau le plus grand que vous avez demandé.Mais si cela correspond à ce que vous faites, cela peut être rentable. Timing informel met
for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}
assez rapide (environ 50 ms pour le 10000 étant donné qu'avec n = 1000000, il a fallu environ 5 secondes), et
for (var n=10000;n>0;n--) {
var b = [];for (var add=10000;add>0;add--) {
b.Push(undefined);
}
}
bien au-dessus d’une minute (environ 90 secondes pour le 10000 sur la même console chrome, ou environ 2000 fois plus lentement). Ce ne sera pas seulement l'allocation, mais aussi les 10000 push, pour la boucle, etc.
var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6
Voici une autre solution
var arr = Array.apply( null, { length: 4 } );
arr; // [undefined, undefined, undefined, undefined] (in Chrome)
arr.length; // 4
Le premier argument de apply()
est une liaison d'objet this, dont nous ne nous soucions pas ici, nous l'avons donc définie sur null
.
Array.apply(..)
appelle la fonction Array(..)
et étale la valeur de l'objet { length: 3 }
en tant qu'argument.
Le constructeur de tableau a un syntaxe ambiguë , et JSLint blesse juste vos sentiments après tout.
En outre, votre exemple de code est cassé, la deuxième instruction var
lève un SyntaxError
. Vous définissez la propriété length
du tableau test
, vous n'avez donc pas besoin d'un autre var
.
En ce qui concerne vos options, array.length
est le seul "propre". La question est, pourquoi avez-vous besoin de définir la taille en premier lieu? Essayez de refactoriser votre code pour vous débarrasser de cette dépendance.
Comme expliqué ci-dessus, utiliser new Array(size)
est quelque peu dangereux. Au lieu de l'utiliser directement, placez-le dans une "fonction de créateur de tableau". Vous pouvez facilement vous assurer que cette fonction est sans bug et vous évitez le danger d'appeler directement new Array(size)
. En outre, vous pouvez lui attribuer une valeur initiale par défaut facultative. Cette fonction createArray
fait exactement cela:
function createArray(size, defaultVal) {
var arr = new Array(size);
if (arguments.length == 2) {
// optional default value
for (int i = 0; i < size; ++i) {
arr[i] = defaultVal;
}
}
return arr;
}
En supposant que la longueur de Array soit constante. En Javascript, voici ce que nous faisons:
const intialArray = new Array(specify the value);
La raison pour laquelle vous ne devriez pas utiliser new Array
est illustrée par ce code:
var Array = function () {};
var x = new Array(4);
alert(x.length); // undefined...
Un autre code pourrait foiré avec la variable Array. Je sais que c'est un peu ridicule que quiconque écrit un tel code, mais quand même ...
En outre, comme Felix King l’a dit, l’interface est un peu incohérente et pourrait donner lieu à des bogues très difficiles à détecter.
Si vous voulez un tableau de longueur = x, rempli avec undefined (comme le ferait new Array(x)
, vous pouvez le faire:
var x = 4;
var myArray = [];
myArray[x - 1] = undefined;
alert(myArray.length); // 4