Когда одна и та же регулярка используется в нескольких местах, велик соблазн вынести её в отдельную переменную и избежать дублирования. Чтобы код после этого неожиданно не сломался, важно знать о неочевидной особенности регулярных выражений с флагом g в JavaScript.
Рассмотрим пример:
const digits = /\d+/;
digits.test("123");
// -> true
digits.test("456");
// -> true
digits.test("789");
// -> true
Всё работает ожидаемо. А теперь добавим флаг g, с которым регулярка должна искать все совпадения:
const digits = /\d+/g;
digits.test("123");
// -> true
digits.test("456");
// -> false
digits.test("789");
// -> true
Теперь проверка срабатывает через раз. Дело в том, что флаг g включает сохранение состояния поиска в поле lastIndex, регулярка становится stateful, а не stateless. При вызове методов test или exec поиск начинается с позиции lastIndex. При отсутствии совпадений lastIndex обнуляется, как президентские сроки, а при обнаружении совпадения в lastIndex записывается позиция после совпадения.
Чтобы избежать этой проблемы, lastIndex можно перезаписывать вручную:
const digits = /\d+/g;
digits.test("123");
// -> true
digits.lastIndex = 0;
digits.test("456");
// -> true
digits.lastIndex = 0;
digits.test("789");
// -> true
К сожалению, это не самое изящное решение, оно добавляет когнитивной нагрузки — нужно помнить о необходимости сброса индекса при каждом поиске. Можно намекать на природу регулярки префиксом stateful или global в названии переменной, чтобы при использовании не забывали обнулять lastIndex; можно писать и использовать собственные функции-обёртки, которые будут обнулять lastIndex при каждом вызове; а можно продолжать хардкодить регулярки в местах их использования — выбор за вами.