JavaScript正则表达式字面量何时编译?

7
根据 MDN的RegExp指南,正则表达式字面量在编译时被编译,而通过调用构造函数创建的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引擎在实践中使用?


1
不确定你如何测试“速度”,但有JSPerf:http://jsperf.com/testing-regexp-define - epascarello
1个回答

5
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浏览器中)。

此外,在您的测试中,您实际上并没有测试构造函数。您只是将第一个测试中的文字面量分配给变量名称。基本上这两个测试是相同的。


1
因此,像通过解析器的一次性评估和重用这样的优化不太可能被实现,因为它违反了MDN的规范。 - Johannes Matokic
另一方面,似乎根本不需要。我测试了更复杂的表达式,与匹配所需的时间相比,编译时间很短(至少对于Firefox 29而言)。因此,如果有许多正则表达式在使用中,可以通过在循环内指定regexp来使代码更易读。 - Johannes Matokic
还应该测试在循环内部调用构造函数。您无法创建完整的正则表达式对象,但可以解析和编译正则表达式而不生成实际的运行时对象。这比不进行优化要快,但比第一个测试要慢。由于它是文字,编译版本是静态的。 - Jamie Pate
1
MDN指南明确建议使用字面量。当脚本加载时,正则表达式字面量提供了对正则表达式的编译。如果正则表达式将保持不变,请使用它以获得更好的性能。那么,应该使用哪个呢? - toniedzwiedz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接