Когда компилируются литералы регулярных выражений JavaScript

Согласно руководству MDN по регулярным выражениям, литералы регулярных выражений компилируются, а Объекты RegExp, созданные путем вызова конструктора, не являются таковыми.

Мой вопрос в том, когда происходит компиляция? Поскольку литерал имеет уникальный синтаксис, во время синтаксического анализа он идентифицируется как регулярное выражение. Это позволило бы скомпилировать его один раз и повторно использовать результат каждый раз, когда он оценивается, в результате чего два примера имеют (почти) одинаковую скорость.

var str = "Hello World";

// Example 1
var regExp1 = /[aeiou]+/gi;
for(var i = 0; i < 1000; ++i)
    regExp1.exec(str);

// Example 2
for(var j = 0; j < 1000; ++j)
    /[aeiou]+/gi.exec(str);

Есть идеи, используется ли это на практике каким-либо JavaScript-движком?


person Johannes Matokic    schedule 23.01.2014    source источник
comment
Не знаю, как вы тестируете скорость, но есть JSPerf: jsperf.com/testing-regexp-define   -  person epascarello    schedule 23.01.2014


Ответы (1)


В документах MDN четко указано, что:

Буквенная нотация обеспечивает компиляцию регулярного выражения при вычислении выражения.

а также

Конструктор объекта регулярного выражения, например, new RegExp("ab+c"), обеспечивает компиляцию регулярного выражения во время выполнения.

Тест, который вы сделали, не очень понятен. Где вы измеряете производительность? Вот как я вижу, что они должны быть сделаны:

start = new Date();
for(var j = 0; j < 1000000; ++j)
    /[aeiou]+/gi.exec(str);
console.log(new Date - start);

start = new Date();
regex = new RegExp("[aeiou]+", "gi");
for(var j = 0; j < 1000000; ++j)
    regex.exec(str);
console.log(new Date - start);

Это производит:

147
118

Понятно, что конструктор быстрее из моих тестов (Chrome)

Также в вашем тесте вы вообще не тестировали конструктор. Вы просто присваивали литерал в первом тесте имени переменной. В основном тесты были идентичными.

person tsikov    schedule 30.03.2014
comment
Так что такая оптимизация, как однократная оценка и повторное использование через парсер, вряд ли будет реализована, так как нарушает спецификацию согласно MDN. - person Johannes Matokic; 15.05.2014
comment
С другой стороны, это, кажется, не требуется вообще. Я тестировал более сложные выражения, и время компиляции мало по сравнению со временем, необходимым для сопоставления (по крайней мере, для Firefox 29). Таким образом, можно сделать код более читабельным, указав регулярное выражение внутри цикла, если используется много регулярных выражений. - person Johannes Matokic; 15.05.2014
comment
Также следует проверить вызов конструктора внутри цикла. Вы не можете создать полный объект регулярного выражения, но вы можете проанализировать и скомпилировать регулярное выражение, не создавая фактический объект для среды выполнения. Это будет быстрее, чем без оптимизации, но медленнее, чем первый тест. Поскольку это литерал, скомпилированная версия является статической. - person Jamie Pate; 22.08.2014
comment
Руководство по MDN явно рекомендует использовать литералы. Литералы регулярных выражений обеспечивают компиляцию регулярного выражения при загрузке скрипта. Когда регулярное выражение останется постоянным, используйте его для повышения производительности. Что это? - person toniedzwiedz; 12.02.2016