Javascript е добре известен със своите странности, но все още се използва широко в програмистката общност. Аз самият използвам Javascript всеки ден, изгарям от него, но продължавам да го използвам.

Наскоро се занимавах с регулярни изрази в Javascript и открих това мистериозно поведение при използване на глобален флаг g.

Нека първо започнем с пример.

const MUSTACHE_REGEX = /{{/g
function hasMustache (template) {
  return MUSTACHE_REGEX.test(template)
}

Функцията hasMustache връща булево значение, независимо дали низът съдържа две последователни фигурни скоби {{ или не.

Сега, ако използвате горната функция два пъти на един и същ низ, тя ще върне true за първи път и след това false.

console.log(hasMustache('Hello {{ username }}')) // true
console.log(hasMustache('Hello {{ username }}')) // false

„Вижте примера на живо“

Защо това се случва?

Javascript съхранява последния съответстващ индекс, когато използва функции test или exec с флаг g.

Което означава, че всеки нов низ, предаден на функцията test, ще започне да съвпада от стария индекс.

console.log(hasMustache('Hello {{ username }}'))
console.log(MUSTACHE_REGEX.lastIndex) // 8

Сега, когато извикаме hasMustache отново, търсенето започна от индекс 8 и следователно нямаше съвпадение.

Да кажем, че променим низа Hello {{ username }} с по-дълъг низ, в който {{ се появява след 8-ия индекс.

console.log(hasMustache('Hello {{ username }}')) console.log(hasMustache('A bit longer string {{ username }}'))

БУМ! Това е true и за двата низа.

Как да поправя?

Използваме флаг g, когато искаме всички срещания на съвпадение и в нашия случай глобалният флаг беше излишен, защото всичко, от което се нуждаехме, беше boolean.

С две думи

  1. Не използвайте g, когато използвате метод regex test.
  2. Когато използвате exec, поставете го в цикъл while, за да получите всички съвпадащи събития.