JavaScript正则表达式文本在函数调用之间保持不变

JavaScript正则表达式文本在函数调用之间保持不变,javascript,regex,Javascript,Regex,我有一段代码: function func1(text) { var pattern = /([\s\S]*?)(\<\?(?:attrib |if |else-if |else|end-if|search |for |end-for)[\s\S]*?\?\>)/g; var result; while (result = pattern.exec(text)) { if (some condition) { thr

我有一段代码:

function func1(text) {

    var pattern = /([\s\S]*?)(\<\?(?:attrib |if |else-if |else|end-if|search |for |end-for)[\s\S]*?\?\>)/g;

    var result;
    while (result = pattern.exec(text)) {
        if (some condition) {
            throw new Error('failed');
        }
        ...
    }
}
函数func1(文本){
var模式=/([\s\s]*?)(\)/g;
var结果;
while(结果=pattern.exec(文本)){
如果(某些条件){
抛出新错误(“失败”);
}
...
}
}
除非执行了throw语句,否则这是有效的。在这种情况下,下次调用该函数时,exec()调用从它停止的地方开始,即使我为它提供了一个新值“text”

我可以通过写作来解决它

var模式=新的RegExp(“…”)

相反,我不明白为什么第一个版本失败了。正则表达式如何在函数调用之间持久化?(最新版本的Firefox和Chrome都出现了这种情况。)

编辑完成测试用例:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
</style>
<script type='text/javascript'>
function func1(text, count) {

    var pattern = /(one|two|three|four|five|six|seven|eight)/g;

    log("func1");
    var result;
    while (result = pattern.exec(text)) {
        log("result[0] = " + result[0] + ", pattern.index = " + pattern.index);
        if (--count <= 0) {
            throw "Error";
        }
    }
}

function go() {
    try { func1("one two three four five six seven eight", 3); } catch (e) { }
    try { func1("one two three four five six seven eight", 2); } catch (e) { }
    try { func1("one two three four five six seven eight", 99); } catch (e) { }
    try { func1("one two three four five six seven eight", 2); } catch (e) { }
}

function log(msg) {
    var log = document.getElementById('log');
    var p = document.createElement('p');
    p.innerHTML = msg;
    log.appendChild(p);
}

</script>
</head>
<body><div>
<input type='button' id='btnGo' value='Go' onclick='go();'>
<hr>
<div id='log'></div>
</div></body>
</html>

测试页
身体{
字体系列:无衬线;
}
#对数p{
保证金:0;
填充:0;
}
函数func1(文本,计数){
var模式=/(一|二|三|四|五|六|七|八)/g;
日志(“func1”);
var结果;
while(结果=pattern.exec(文本)){
日志(“结果[0]=”+结果[0]+”,pattern.index=“+pattern.index”);

如果(--count我不知道答案,但我会冒险猜测:


作为模式的文本表达式具有全局作用域,并且只计算(到RegExp对象中)一次,而如果使用
new RegExp
,它的参数仍然是全局的,但只是一个字符串,而不是RegExp。

我将在这里冒险:我认为您看到的行为是FF和Chrome的Javascript引擎中的一个bug(异端邪说!)。令人惊讶的是,它竟然发生在两个如此不同的发动机上。看起来像是一个优化错误。具体来说,第7.8.5节说:

正则表达式文本是一个输入元素,每次计算该文本时,它都会转换为RegExp对象(请参见15.10)

我看到的唯一回旋余地是短语“.每次计算文字”(我的重点)。但我不明白为什么结果对象应该比任何其他对象文字更神奇地保留,例如:

function func1() {
    var x = {};
    return x;
}
在那里,对
func1
的后续调用将为您提供不同的对象。因此,我认为这看起来像一个bug


更新Alan Moore,Levithan在其中声称ECMAScript第3版规范可能允许这种缓存。幸运的是,从ECMAScript第5版(我使用的规范)开始,它就不被允许了因此,很快就会成为一个bug。谢谢Alan!

通过regex文本创建的RegExp对象会被缓存,但是
新RegExp
总是创建一个新对象。缓存的对象也会保存它们的状态,但是管理这方面的规则显然不是很清楚。Steve Levithan在(靠近底部).

我已经冒昧地发布了一个完整、简化的测试用例,希望您不要介意。我也看到过这种行为,并想知道为什么会这样。它看起来和闻起来都像一个bug,但有时事情非常微妙,令人惊讶的是,FF和Chrome都会使用完全不同的底层Javascript engi说明一下,只要没有抛出错误/异常,它就可以工作,但如果“某个条件”变为true并抛出异常,那么函数在下一次调用时将失败,因为该模式从抛出异常的位置继续?这听起来确实像是一个不可控制的错误。@Colin:除非它没有global scope,比
var x={};
中的对象更具有全局作用域。这也是一个文本,但每次函数调用都会得到不同的对象。博客上说它将在Firefox 3.7中修复(我现在使用的是3.6.3)。我想我会停止使用RE-literal,作为这种行为的跨浏览器解决方案。非常好,谢谢。请注意,“…被缓存…”应该是“…被ECMAScript第三版的一些实现缓存…”,然后声明从最新规范起它们可能不再被缓存(谢天谢地!).@Charles:如果你停止使用文字,你将受到转义规则的伤害。:-)只需在使用前重置
lastIndex
(除非你在实例化后还乱用其他标志)。并且很高兴最新的规范修复了这个小愚蠢。