Pourquoi le modificateur "g" donne-t-il des résultats différents lorsque le test () s'appelle deux fois?

Compte tenu de ce code:

var reg = /a/g; console.log(reg.test("a")); console.log(reg.test("a")); 

Je reçois ce résultat:

 true false 

Je ne sais pas comment cela pourrait se produire. J'ai testé à la fois dans Node.js (v8) et Firefox.

Pour contourner le problème, vous pouvez supprimer le drapeau g ou réinitialiser lastIndex comme dans

 var reg = /a/g; console.log(reg.test("a")); reg.lastIndex = 0; console.log(reg.test("a")); 

Le problème se pose parce que le test est basé sur exec qui recherche d'autres correspondances après le premier s'il a passé la même chaîne et que le drapeau g est présent.

15.10.6.3 RegExp.prototype.test(string) # Ⓣ Ⓡ

Les étapes suivantes sont prises:

  1. Laissez correspondre le résultat de l'évaluation de l' RegExp.prototype.exec (15.10.6.2) sur cet objet RegExp utilisant la chaîne comme argument.
  2. Si la correspondance n'est pas null , retournez true ; Sinon retourner false .

La partie clé de exec est l'étape 6 de 15.10.6.2 :

6. Laissez global être le résultat d'appeler la méthode interne [[Get]] de R avec l'argument "global".
7. Si global est faux, laissez i = 0.

Lorsque i n'est pas réinitialisé à 0, alors exec (et donc test ) ne commence pas à regarder le début de la chaîne.

Ceci est utile pour exec car vous pouvez faire une boucle pour gérer chaque correspondance:

  var myRegex = /o/g; var myString = "fooo"; for (var match; match = myRegex.exec(myString);) { alert(match + " at " + myRegex.lastIndex); } 

Mais évidemment ce n'est pas si utile pour le test .

Habituellement, un test est choisi pour vérifier si un certain motif correspond au tout, mais l'indicateur global vous permet de passer une chaîne à compter les correspondances ou, comme exec, faire quelque chose avec chaque lastIndex. Une autre utilisation est de définir le dernierIndex du rx vous-même avant que le test ne soit effectué, d'ignorer les correspondances avant un indice de personnage.

 var count=0, rx=/\s+/g, rx.lastIndex=100; while(rx.test(string))count++;