我有这段代码:
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');
}
...
}
}
这是有效的,除非执行throw语句。在这种情况下,下次调用该函数时,exec()调用会在它停止的地方开始,即使我为它提供了一个新的'text'值。
我可以通过编写
来解决这个问题var pattern = new 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>
正则表达式在FF和Chrome上的第二次调用时继续为'4',而不是在IE7或Opera上。
答案 0 :(得分:7)
通过正则表达式文字创建的RegExp对象被缓存,但new RegExp
始终创建一个新对象。缓存的对象也保存它们的状态,但是管理该方面的规则显然不是很清楚。 Steve Levithan在this blog post(靠近底部)谈论这个问题。
答案 1 :(得分:1)
我会在这里说清楚:我认为你所看到的行为是FF和Chrome的Javascript引擎中的一个错误(异端邪说!)。但令人惊讶的是它应该发生在两个这样的不同引擎中。看起来像是一个优化错误。具体而言,the spec的第7.8.5节说:
正则表达式文字是一个输入元素,每次评估文字时都会转换为RegExp对象(见15.10)。
我看到的唯一一个摆动的房间是“..每次评估文字 ”(我的重点)。但我不明白为什么生成的对象应该被神奇地保留,而不是任何其他对象文字,例如:
function func1() {
var x = {};
return x;
}
在那里,对func1
的后续调用将为您提供不同的对象。因此我的说法对我来说看起来像个错误。
更新 Alan Moore points to和article by Steve Levithan,其中Levithan声称ECMAScript第3版规范可能允许此类缓存。幸运的是,从ECMAScript第5版(我正在制作的规范)开始,它是不允许的,因此,它将成为Real Soon Now的错误。谢谢Alan!
答案 2 :(得分:0)
我不知道答案,但我会冒险猜测:
作为模式的文字表达式具有全局范围,并且仅被评估(进入RegExp对象)一次,而如果使用new Regexp
,它的参数仍然是全局的,但只是一个字符串,而不是一个RegExp 。