Ce qu'ils ne vous ont pas dit à propos des extras Array d'ES5

Chaque nouvelle version de JavaScript ajoute des avantages supplémentaires qui facilitent la programmation. EcmaScript 5 a ajouté quelques méthodes indispensables à la Tableau type de données et, bien que vous puissiez trouver des ressources qui vous apprennent à utiliser ces méthodes, elles omettent généralement de discuter de leur utilisation avec autre chose qu'une fonction ennuyeuse et personnalisée.

Tous les extras du tableau sont ignorés des trous dans des tableaux.

Les nouvelles méthodes de tableau ajoutées dans ES5 sont généralement appelées Extras de tableau. Ils facilitent le processus de travail avec les baies en fournissant des méthodes pour effectuer des opérations courantes. Voici une liste presque complète des nouvelles méthodes:

  • Array.prototype.map
  • Array.prototype.reduce
  • Array.prototype.reduceRight
  • Array.prototype.filter
  • Array.prototype.forEach
  • Array.prototype.every
  • Array.prototype.some

Array.prototype.indexOf et Array.prototype.lastIndexOf font également partie de cette liste, mais ce tutoriel ne traitera que des sept méthodes ci-dessus..


Ce qu'ils vous ont dit

Ces méthodes sont assez simples à utiliser. Ils exécutent une fonction que vous fournissez comme premier argument pour chaque élément du tableau. En règle générale, la fonction fournie doit avoir trois paramètres: l'élément, l'index de l'élément et le tableau entier. Voici quelques exemples:

[1, 2, 3] .map (fonction (elem, index, arr) return elem * elem;); // retourne [1, 4, 9] [1, 2, 3, 4, 5] .filter (fonction (elem, index, arr) return elem% 2 === 0;); // retourne [2, 4] [1, 2, 3, 4, 5] .some (fonction (elem, index, arr) return elem> = 3;); // renvoie true [1, 2, 3, 4, 5] .every (fonction (elem, index, arr) return elem> = 3;); // retourne faux

le réduire et réduire à droite les méthodes ont une liste de paramètres différente. Comme leur nom l'indique, ils réduisent un tableau à une seule valeur. La valeur initiale du résultat correspond par défaut au premier élément du tableau, mais vous pouvez passer un second argument à ces méthodes pour servir de valeur initiale..

La fonction de rappel pour ces méthodes accepte quatre arguments. L'état actuel est le premier argument et les arguments restants sont l'élément, l'index et le tableau. Les extraits suivants illustrent l'utilisation de ces deux méthodes:

[1, 2, 3, 4, 5] .reduce (fonction (sum, elem, index, arr) return sum + elem;); // retourne 15 [1, 2, 3, 4, 5] .reduce (fonction (sum, elem, index, arr) return sum + elem;, 10); // retourne 25

Mais vous saviez probablement déjà tout cela, n'est-ce pas? Passons donc à quelque chose que vous ne connaissez peut-être pas.


Programmation fonctionnelle à la rescousse

C’est étonnant que plus de gens ne le sachent pas: vous n’avez pas besoin de créer une nouvelle fonction et de la transmettre à .carte() et amis. Mieux encore, vous pouvez passer des fonctions intégrées, telles que parseFloat sans emballage requis!

["1", "2", "3", "4"]. Map (parseFloat); // retourne [1, 2, 3, 4]

Notez que certaines fonctions ne fonctionneront pas comme prévu. Par exemple, analyse accepte une base comme second argument. Rappelez-vous maintenant que l'index de l'élément est transmis à la fonction en tant que second argument. Alors, quel sera le retour suivant?

["1", "2", "3", "4"]. Map (parseInt);

Exactement: [1, NaN, NaN, NaN]. Comme explication: la base 0 est ignorée; ainsi, la première valeur est analysée comme prévu. Les bases suivantes n'incluent pas le nombre passé en tant que premier argument (par exemple, la base 2 n'inclut pas 3), ce qui conduit à NaNs. Assurez-vous donc de vérifier dès le départ le réseau de développeurs Mozilla avant d’utiliser une fonction et vous serez prêt à partir..

Astuce: Vous pouvez même utiliser des constructeurs intégrés comme arguments, car ils ne doivent pas nécessairement être appelés avec Nouveau. Par conséquent, une conversion simple en valeur booléenne peut être effectuée à l'aide de Booléen, comme ça:

["oui", 0, "non", "", "vrai", "faux"]. filter (Boolean); // retourne ["oui", "non", "vrai", "faux"]

Quelques autres fonctions intéressantes sont encodeURIComponent, Date.parse (notez que vous ne pouvez pas utiliser le Rendez-vous amoureux constructeur car il renvoie toujours la date du jour lorsqu'il est appelé sans Nouveau), Array.isArray et JSON.parse.


N'oubliez pas de .appliquer()

Bien que l’utilisation de fonctions intégrées en tant qu’arguments pour les méthodes de tableau puisse constituer une bonne syntaxe, vous devez également vous rappeler que vous pouvez passer un tableau comme second argument Function.prototype.apply. C’est pratique, quand on appelle des méthodes, comme Math.max ou String.fromCharCode. Les deux fonctions acceptant un nombre variable d'arguments, vous devez donc les envelopper dans une fonction lorsque vous utilisez les extras de tableau. Donc au lieu de:

var arr = [1, 2, 4, 5, 3]; var max = arr.reduce (fonction (a, b) return Math.max (a, b););

Vous pouvez écrire ce qui suit:

var arr = [1, 2, 4, 5, 3]; var max = Math.max.apply (null, arr);

Ce code présente également un avantage en termes de performances. Remarque: dans EcmaScript 6, vous pourrez simplement écrire:

var arr = [1, 2, 4, 5, 3]; var max = Math.max (… arr); // CECI NE FONCTIONNE PAS ACTUELLEMENT!

Tableaux sans trous

Tous les extras du tableau sont ignorés des trous dans des tableaux. Un exemple:

var a = ["bonjour",,,,, "monde"]; // un [1] à un [4] ne sont pas définis var count = a.reduce (function (count) return count + 1;, 0); console.log (count); // 2

Ce comportement présente probablement un avantage en termes de performances, mais il existe des cas où il peut être très pénible. Un tel exemple pourrait être quand vous avez besoin d'un tableau de nombres aléatoires; il n'est pas possible d'écrire simplement ceci:

var randomNums = new Array (5) .map (Math.random);

Mais rappelez-vous que vous pouvez appeler tous les constructeurs natifs sans Nouveau. Et une autre friandise utile: Function.prototype.apply n'ignore pas les trous. En combinant ces éléments, ce code renvoie le résultat correct:

var randomNums = Array.apply (null, new Array (5)). map (Math.random);

Le deuxième argument inconnu

La plupart de ce qui précède est connu et utilisé régulièrement par de nombreux programmeurs. Ce que la plupart d’entre eux ne savent pas (ou du moins n’utilisent pas) est le deuxième argument de la plupart des extras de tableau (seulement le réduire* les fonctions ne le supportent pas).

En utilisant le second argument, vous pouvez passer un ce valeur à la fonction. En conséquence, vous pouvez utiliser prototype-méthodes. Par exemple, filtrer un tableau avec une expression régulière devient une ligne:

["foo", "bar", "baz"]. filter (RegExp.prototype.test, / ^ b /); // retourne ["bar", "baz"]

Aussi, vérifier si un objet a certaines propriétés devient un jeu d'enfant:

["foo", "isArray", "create"]. some (Object.prototype.hasOwnProperty, Object); // retourne vrai (à cause de Object.create)

En fin de compte, vous pouvez utiliser toutes les méthodes que vous souhaitez:

// permet de faire quelque chose de fou [function (a) return a * a; , fonction (b) retourne b * b * b; ] .map (Array.prototype.map, [1, 2, 3]); // retourne [[1, 4, 9], [1, 8, 27]]

Cela devient fou lorsque vous utilisez Function.prototype.call. Regarde ça:

["foo", "\ n \ tbar", "\ r \ nbaz \ t"] .map (Function.prototype.call, String.prototype.trim); // retourne ["foo", "bar", "baz"] [true, 0, null, []]. map (Function.prototype.call, Object.prototype.toString); // retourne ["[objet Booléen]", "[numéro d'objet]", "[objet Null]", "[objet Array]"]

Bien sûr, pour faire plaisir à votre geek intérieur, vous pouvez également utiliser Function.prototype.call comme second paramètre. Ce faisant, chaque élément du tableau est appelé avec son index comme premier argument et le tableau entier comme second:

[function (index, arr) // tout ce que vous pourriez vouloir en faire]. forEach (Function.prototype.call, Function.prototype.call);

Permet de construire quelque chose d'utile

Cela dit, construisons une simple calculatrice. Nous voulons seulement soutenir les opérateurs de base (+, -, *, /), et nous devons respecter la procédure de l'opérateur. Donc, multiplication (*) et division (/) doivent être évalués avant l'addition (+) et soustraction (-).

Tout d'abord, nous définissons une fonction qui accepte une chaîne représentant le calcul comme premier et unique argument.

fonction calculer (calcul) 

Dans le corps de la fonction, nous commençons à convertir le calcul en tableau en utilisant une expression régulière. Ensuite, nous nous assurons d’avoir analysé l’ensemble du calcul en joignant les pièces à l’aide de Array.prototype.join et en comparant le résultat avec le calcul original.

var parts = computing.match (// digits | opérateurs | espaces | /(?:\-?[\d\.hner+)|[-\+\\\\/****/g); if (calcul! == parts.join ("")) lance une nouvelle erreur ("impossible d'analyser le calcul")

Après cela, nous appelons String.prototype.trim pour chaque élément d'éliminer les espaces blancs. Ensuite, nous filtrons le tableau et retirons les éléments falsey (ie: f chaînes vides).

parts = parts.map (Function.prototype.call, String.prototype.trim); parts = parts.filter (Boolean);

Maintenant, nous construisons un tableau séparé qui contient des nombres analysés.

var nums = parts.map (parseFloat);

Vous pouvez transmettre des fonctions intégrées telles que parseFloat sans emballage requis!

À ce stade, le moyen le plus simple de continuer est un simple pour-boucle. Dans ce cadre, nous construisons un autre tableau (nommé traité) avec multiplication et division déjà appliquées. L'idée de base est de réduire chaque opération à une addition, de sorte que la dernière étape devienne assez triviale.

Nous vérifions chaque élément du nums tableau pour s'assurer que ce n'est pas NaN; si ce n'est pas un nombre, c'est un opérateur. Le moyen le plus simple de le faire est de tirer parti du fait qu'en JavaScript,, NaN! == NaN. Lorsque nous trouvons un nombre, nous l'ajoutons au tableau de résultats. Quand on trouve un opérateur, on l'applique. Nous ignorons les opérations d'addition et ne modifions que le signe du prochain nombre à soustraire.

La multiplication et la division doivent être calculées en utilisant les deux nombres environnants. Comme nous avons déjà ajouté le numéro précédent au tableau, il doit être supprimé à l'aide de Array.prototype.pop. Le résultat du calcul est ajouté au tableau de résultats, prêt à être ajouté.

var traité = []; pour (var i = 0; i < parts.length; i++) if( nums[i] === nums[i] ) processed.push( nums[i] );  else  switch( parts[i] )  case "+": continue; //ignore case "-": processed.push(nums[++i] * -1); break; case "*": processed.push(processed.pop() * nums[++i]); break; case "/": processed.push(processed.pop() / nums[++i]); break; default: throw new Error("unknown operation: " + parts[i]);   

La dernière étape est assez facile: nous ajoutons tous les nombres et renvoyons notre résultat final.

return processing.reduce (function (result, elem) return result + elem;);

La fonction complétée devrait ressembler à ceci:

function calcule (calcul) // construit un tableau contenant les différentes parties var parties = calcul.match (// digits | opérateurs | espaces | (?: \ -? [\ d \.] +) | [- \ + \ * \ /] | \ s + / g); // teste si tout correspondait si (calcul! == parts.join ("")) lance une nouvelle erreur ("impossible d'analyser le calcul") // supprime tous les espaces blancs parts = parts.map (Function.prototype. appel, String.prototype.trim); parts = parts.filter (Boolean); // construit un tableau séparé contenant des nombres analysés var nums = parts.map (parseFloat); // construit un autre tableau avec toutes les opérations réduites à des ajouts var processing = []; pour (var i = 0; i < parts.length; i++) if( nums[i] === nums[i] ) //nums[i] isn't NaN processed.push( nums[i] );  else  switch( parts[i] )  case "+": continue; //ignore case "-": processed.push(nums[++i] * -1); break; case "*": processed.push(processed.pop() * nums[++i]); break; case "/": processed.push(processed.pop() / nums[++i]); break; default: throw new Error("unknown operation: " + parts[i]);    //add all numbers and return the result return processed.reduce(function(result, elem) return result + elem; ); 

Ok, alors testons-le:

calcule ("2 + 2.5 * 2") // renvoie 7 calcule ("12/6 + 4 * 3") // renvoie 14

Cela semble fonctionner! Il y a encore des cas marginaux qui ne sont pas traités, tels que les calculs effectués par l'opérateur ou les nombres contenant plusieurs points. Prendre en charge les parenthèses serait bien, mais nous n’allons pas chercher plus de détails dans cet exemple simple.


Emballer

Bien que les suppléments de tableau de ES5 puissent sembler au début assez triviaux, ils révèlent un peu de profondeur une fois que vous leur en donnez la chance. Du coup, la programmation fonctionnelle en JavaScript devient plus que du code de rappel et du code spaghetti. Réaliser cela m'a vraiment ouvert les yeux et a influencé ma façon d'écrire les programmes.

Bien entendu, comme indiqué ci-dessus, il existe toujours des cas où vous souhaitez utiliser une boucle normale. Mais, et c'est la bonne partie, vous n'avez pas besoin de.