Comment initialiser la longueur d'un tableau dans javascript?

La plupart des didacticiels que j'ai lus sur les tableaux en JavaScript (y compris w3schools et devguru ) suggèrent que vous pouvez initialiser un tableau avec une certaine longueur en transmettant un nombre entier au constructeur Array en utilisant le var test = new Array(4); syntaxe.

Après avoir utilisé cette syntaxe généreusement dans mes fichiers js, j'ai couru l'un des fichiers via jsLint , et il s'est effrayé:

Erreur: Problème à la ligne 1 du caractère 22: Attente de ')' et à la place '' 4 ''.
Var test = new Array (4);
Problème à la ligne 1 caractère 23: Prévu ';' Et a plutôt vu ')'.
Var test = new Array (4);
Problème à la ligne 1 caractère 23: Un identifiant attendu et plutôt vu ')'.

Après avoir lu l'explication de jsLint sur son comportement , il semble que jsLint n'aime pas vraiment la new Array() syntaxe new Array() et préfère plutôt [] lors de la déclaration de tableaux.

J'ai donc quelques questions. Tout d'abord, pourquoi? Est-ce que je courus un risque en utilisant la new Array() syntaxe new Array() place? Y at-il des incompatibilités de navigateur que je devrais connaître? Deuxièmement, si je passe à la syntaxe du crochet carré, est-il possible 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; 

  1. Pourquoi voulez-vous initialiser la longueur? Théoriquement, il n'y a pas besoin de cela. Cela peut même entraîner des comportements déroutants, car tous les tests qui utilisent la length pour déterminer si un tableau est vide ou non indiquent que le tableau n'est pas vide.
    Certains tests montrent que le réglage de la longueur initiale des grands tableaux peut être plus efficace si le tableau est rempli par la suite, mais le gain de performance (le cas échéant) semble différer du navigateur au navigateur.

  2. JsLint n'aime pas new Array() car le constructeur est ambigu.

     new Array(4); 

    Crée un ensemble vide de longueur 4. Mais

     new Array('4'); 

    Crée un tableau contenant la valeur '4' .

En ce qui concerne votre commentaire: Dans JS, vous n'avez pas besoin d'initialiser la longueur du tableau. Il se développe 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 avec la longueur 5 mais pas de valeurs, donc vous ne pouvez pas l'itérer sur elle.

  • Array.apply(null, Array(5)).map(function () {}) vous donne un tableau de longueur 5 et indéfini en tant que valeurs, maintenant il peut être itéré.

  • Array.apply(null, Array(5)).map(function (x, i) { return i; }) vous donne un tableau avec la longueur 5 et les 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 alors maintenant vous pouvez également utiliser Array.from(Array(5)).forEach(alert)

  • Si vous souhaitez initialiser avec une certaine valeur de chaîne, Array.from('abcde') ou Array.from('x'.repeat(5)) est bon à savoir …

Avec .fill() vous pouvez maintenant simplement:

 //n is the size you want to initialize your array Array(n).fill(0) 

Ce qui est beaucoup plus concis que Array.apply(0, new Array(n)).map(i => 0)

Cela initialisera la propriété length en 4:

 var x = [,,,,]; 

Je suis surpris qu'il n'y ait pas eu de solution fonctionnelle suggérée qui vous permet de définir la longueur en 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, j'éviterais de faire cela sauf si je voulais initialiser le tableau à une valeur spécifique. Il est intéressant de noter qu'il existe d'autres bibliothèques qui implémentent la gamme, y compris Lo-dash et Lazy, qui peuvent avoir différentes caractéristiques de performance.

(C'était probablement mieux en tant que commentaire, mais trop longtemps)

Donc, après avoir lu cela, j'étais curieux de savoir si la pré-allocation était en réalité plus rapide, car en théorie elle devrait l'être. Cependant, ce blog a donné quelques conseils pour le conseiller http://www.html5rocks.com/en/tutorials/speed/v8/ .

Tout en restant incertain, je l'ai mis à l'épreuve. Et comme il s'avère qu'il semble ê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 produit ce qui suit après quelques courses 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 

La raison pour laquelle vous ne devriez pas utiliser une new Array est démontrée par ce code:

 var Array = function () {}; var x = new Array(4); alert(x.length); // undefined... 

Un autre code pourrait être utilisé avec la variable Array. Je sais que c'est un peu lointain que quelqu'un écrirait un tel code, mais encore …

En outre, comme l'a déclaré Felix King, l'interface est un peu incohérente et pourrait conduire à des bugs très difficiles à retrouver.

Si vous vouliez un tableau avec length = x, rempli de indéfinis (comme le ferait une new Array(x) ), vous pouvez le faire:

 var x = 4; var myArray = []; myArray[x - 1] = undefined; alert(myArray.length); // 4 
 var arr=[]; arr[5]=0; alert("length="+arr.length); // gives 6 

Le constructeur de réseau a une syntaxe ambiguë , et JSLint fait juste mal à vos sentiments après tout.

En outre, votre code d'exemple est brisé, la deuxième instruction var SyntaxError un SyntaxError . Vous définissez la length de la propriété du test tableau, donc il n'y a pas besoin d'une autre var .

En ce qui concerne vos options, array.length est le seul "propre". La question est, pourquoi devez-vous définir la taille en premier lieu? Essayez de refactoriser votre code pour vous débarrasser de cette dépendance.

S'il vous plaît, les gens n'abandonnent pas encore vos anciennes habitudes. Il existe une grande différence de complexité entre l'affectation de la mémoire une fois que vous travaillez avec les entrées de ce tableau (à partir de l'ancien) et l'affectez plusieurs fois à mesure qu'un réseau augmente (ce qui est inévitablement ce que le système fait sous le capot avec d'autres méthodes suggérées) .

Rien de tout cela ne dépend bien sûr, jusqu'à ce que vous vouliez faire quelque chose de cool avec des tableaux plus grands. Ensuite, il le fait.

Comme il semble toujours qu'il n'y ait aucune option dans JS pour définir la capacité initiale d'un tableau, j'utilise les éléments suivants …

 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:

  • Cette méthode prend aussi longtemps que les autres pour le premier appel à la fonction, mais très peu de temps pour les appels ultérieurs (à moins de demander un plus grand tableau).
  • Le réseau standard réserve en permanence autant d'espace que le plus grand réseau que vous avez demandé.

Mais si cela correspond à ce que vous faites, il peut y avoir un gain. Le calendrier informel met

 for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;} 

À très vite (environ 50 ms pour le 10000 étant donné que 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 plus d'une minute (environ 90 sec pour le 10000 sur la même console chrome, ou environ 2000 fois plus lent). Ce ne sera pas seulement l'allocation, mais aussi les 10000 pousses, pour la boucle, etc.

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 un objet contraignant, dont nous ne nous intéressons pas, alors nous l'avons mis à null .

Array.apply(..) appelle la fonction Array(..) et répand la valeur d'objet { length: 3 } comme ses arguments.

Comme expliqué ci-dessus, utiliser une new Array(size) est quelque peu dangereux. Au lieu de l'utiliser directement, placez-le dans une "fonction de création de tableau". Vous pouvez facilement vous assurer que cette fonction est sans bug et vous évitez le risque d'appeler une new Array(size) directement. En outre, vous pouvez lui donner une valeur initiale par défaut optionnelle. 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; } 

Vous pouvez définir la longueur du tableau en utilisant array.length = youValue

Donc ce serait

 var myArray = []; myArray.length = yourValue;