Javascript Regex literal с /g используется несколько раз

У меня есть странная проблема, работающая с функцией Javascript Regexp.exec. При вызове многократного использования функции в новых (я думаю...) регулярных объектах, она работает один раз каждые два. Я не понимаю почему!

Вот пример небольшого цикла, но он делает то же самое, когда используется один раз в функции и вызывается несколько раз.

for (var i = 0; i < 5; ++i) {
  console.log(i, (/(b)/g).exec('abc'));
}

> 0 ["b", "b"]
> 1 null
> 2 ["b", "b"]
> 3 null
> 4 ["b", "b"]

При удалении /g он возвращается к нормальному.

for (var i = 0; i < 5; ++i) {
  console.log(i, (/(b)/).exec('abc'));
}             /* no g ^ */

> 0 ["b", "b"]
> 1 ["b", "b"]
> 2 ["b", "b"]
> 3 ["b", "b"]
> 4 ["b", "b"]

Я предполагаю, что существует оптимизация, сохраняющая объект регулярного выражения, но это кажется странным.

В Chrome 4 и Firefox 3.6 такое поведение одинаково, но в IE8 оно работает как (I). Я считаю, что это предназначено, но я не могу найти там логику, может быть, вы сможете мне помочь!

Спасибо

Ответы

Ответ 1

/g не предназначен для простого сопоставления:

/g позволяет "глобальное" сопоставление. При использовании метода replace() укажите этот модификатор, чтобы заменить все совпадения, а не только первый.

Я бы предположил, что внутри javascript сохраняет соответствие после захвата, поэтому он сможет возобновить соответствие, и поэтому возвращается null, так как b происходит только один раз в теме. Для сравнения:

for (var i = 0; i < 5; ++i) {
  console.log(i +'    ' + (/(b+)/g).exec("abbcb"));
}

возвращает:

0 bb,bb
1 b,b
2 null
3 bb,bb
4 b,b

Ответ 2

Если вы собираетесь использовать одно и то же регулярное выражение, выведите его из цикла и явно reset it:

var pattern = /(b)/g;
for (var i = 0; i < 5; ++i) {
  pattern.lastIndex = 0;
  console.log(i + ' ' + pattern.exec("abc"));
}

Ответ 3

Спасибо:)

Я нашел интересный побочный эффект, он может сделать статическую переменную (в смысле C, глобальную, но только видимую от функции) без закрытия!

   function test () {
     var static = /a/g;
     if ('count' in static) {
       static.count++;
     } else {
       static.count = 1;
     }
     console.log(static.count);
   }

   for (var i = 0; i < 5; ++i) { test(); }
   1
   2
   3
   4
   5

(Я делаю новый ответ, потому что мы не можем помещать код внутри комментария)