Как часто JavaScript перекомпилирует регулярные выражения в функциях?
Учитывая эту функцию:
function doThing(values,things){
var thatRegex = /^http:\/\//i; // is this created once or on every execution?
if (values.match(thatRegex)) return values;
return things;
}
Как часто JavaScript-движок должен создавать регулярное выражение? Один раз за выполнение или один раз на загрузку страницы / script разбор?
Чтобы избежать ненужных ответов или комментариев, я лично предпочитаю использовать регулярное выражение вне функции, а не внутри. Речь идет о поведении языка, потому что я не уверен, где искать это, или если это проблема с двигателем.
EDIT:
Мне напомнили, что я не упоминал, что это будет использоваться в цикле. Мои извинения:
var newList = [];
foreach(item1 in ListOfItems1){
foreach(item2 in ListOfItems2){
newList.push(doThing(item1, item2));
}
}
Поэтому, учитывая, что он будет использоваться много раз в цикле, имеет смысл определить регулярное выражение вне функции, но так, чтобы идея.
также обратите внимание, что script довольно обобщен с целью изучения только поведения и стоимости создания регулярных выражений
Ответы
Ответ 1
В javascript есть два объекта типа "регулярное выражение".
экземпляры регулярного выражения и объект RegExp.
Кроме того, существует два способа создания экземпляров регулярных выражений:
- с использованием синтаксиса/regex/и
- с использованием нового RegExp ('regex');
Каждый из них каждый раз создает новый экземпляр регулярного выражения.
Однако существует только ОДИН глобальный объект RegExp.
var input = 'abcdef';
var r1 = /(abc)/;
var r2 = /(def)/;
r1.exec(input);
alert(RegExp.$1); //outputs 'abc'
r2.exec(input);
alert(RegExp.$1); //outputs 'def'
Фактический шаблон скомпилирован, когда загружается script, когда вы используете синтаксис 1
Аргумент шаблона перед использованием компилируется во внутренний формат. Для синтаксиса 1 шаблон компилируется при загрузке script. Для синтаксиса 2 шаблон компилируется непосредственно перед использованием или когда вызывается метод компиляции.
Но вы все равно можете получить разные экземпляры регулярных выражений, каждый вызов метода. Тест в chrome vs firefox
function testregex() {
var localreg = /abc/;
if (testregex.reg != null){
alert(localreg === testregex.reg);
};
testregex.reg = localreg;
}
testregex();
testregex();
Это ОЧЕНЬ немного накладных расходов, но если вы хотите ровно одно регулярное выражение, его безопаснее всего создать один экземпляр вне вашей функции
Ответ 2
Из Руководство по JavaScript Mozilla в регулярных выражениях:
Литералы регулярных выражений обеспечивают компиляцию регулярного выражения при оценке script. Когда регулярное выражение останется постоянным, используйте его для повышения производительности.
И из спецификация ECMA-262, §7.8.5 Литералы регулярного выражения:
Литерал регулярных выражений - это элемент ввода, который преобразуется в объект RegExp (см. 15.10) каждый раз, когда литерал оценивается.
Другими словами, он скомпилирован один раз, когда он оценивается как script, сначала анализируется.
Стоит также отметить, что из спецификации ES5 два литерала будут скомпилированы в два разных экземпляра RegExp
, даже если сами литералы одинаковы. Таким образом, если данный литерал появляется дважды внутри вашего script, он будет скомпилирован дважды, в два разных экземпляра:
Два литерала регулярных выражений в программе оценивают объекты регулярного выражения, которые никогда не сравниваются как === друг с другом, даже если содержимое двух литералов идентично.
...
... каждый раз, когда литерал оценивается, новый объект создается, как если бы выражение new RegExp(Pattern, Flags)
, где RegExp является стандартным встроенным конструктором с этим именем.
Ответ 3
Регулярное выражение будет скомпилировано каждый раз, когда вы вызываете функцию , если она не в литеральной форме.
Поскольку вы включаете его в буквальную форму, вам не о чем беспокоиться.
Здесь цитата из websina.com:
Литералы регулярных выражений обеспечивают компиляцию регулярного выражения при оценке script. Когда регулярное выражение останется постоянным, используйте его для повышения производительности.
Вызов функции-конструктора объекта RegExp следующим образом: re = new RegExp("ab+c")
Использование функции конструктора обеспечивает компиляцию регулярного выражения во время выполнения. Используйте функцию конструктора, когда вы знаете, что шаблон регулярного выражения будет меняться, или вы не знаете шаблон и получаете его из другого источника, такого как ввод пользователя.
Ответ 4
Предоставленные ответы не позволяют четко различать два разных процесса за сценой: создание регекса и создание регулярного выражения при нажатии выражения создания объекта regexp.
Да, используя синтаксис литералов regexp, вы получаете преимущество в производительности одноразовой компиляции регулярного выражения.
Но если ваш код выполняется в среде ES5 +, каждый раз, когда путь кода входит в функцию doThing()
в вашем примере, он фактически создает новый объект RegExp
, но без необходимости компилирования regexp снова и снова.
В ES5 литеральный синтаксис создает новый объект RegExp
каждый раз, когда путь кода обращается к выражению, которое создает регулярное выражение через литерал:
function getRE() {
var re = /[a-z]/;
re.foo = "bar";
return re;
}
var reg = getRE(),
re2 = getRE();
console.log(reg === re2); // false
reg.foo = "baz";
console.log(re2.foo); // "bar"
Чтобы проиллюстрировать приведенные выше утверждения с точки фактических чисел, взгляните на разницу в производительности между тестами storedRegExp
и inlineRegExp
в этом jsperf.
storedRegExp
будет примерно на 5-20% быстрее в браузерах, чем inlineRegExp
- накладные расходы на создание (и сбор мусора) нового объекта RegExp
каждый раз.
вывод представляется:
Если вы сильно используете литеральные регулярные выражения, подумайте о том, чтобы кэшировать их за пределами области, в которой они нужны, чтобы их не только компилировали один раз, но и реальные объекты регулярного выражения для них также создавались один раз.