Javascript 带有/g修饰符和eval的正则表达式文字-FireFox和Chrome中的怪异行为
我在一些javascript代码中遇到了一些奇怪的行为,但仅在Firefox和Chrome中。我很好 我已经隔离了这个问题,并创建了一个小页面,这样您就可以自己查看行为 本质上,它看起来就像是MethodC中的正则表达式对象在对MethodC的方法调用中被重用,即使它是一个局部变量。有人能解释一下这种行为吗Javascript 带有/g修饰符和eval的正则表达式文字-FireFox和Chrome中的怪异行为,javascript,regex,firefox,google-chrome,Javascript,Regex,Firefox,Google Chrome,我在一些javascript代码中遇到了一些奇怪的行为,但仅在Firefox和Chrome中。我很好 我已经隔离了这个问题,并创建了一个小页面,这样您就可以自己查看行为 本质上,它看起来就像是MethodC中的正则表达式对象在对MethodC的方法调用中被重用,即使它是一个局部变量。有人能解释一下这种行为吗 <html> <head> <script type="text/javascript"> function RunDemo() {
<html>
<head>
<script type="text/javascript">
function RunDemo()
{
var subject = "01234 555 6789";
for (var i = 1; i <= 10; i++) {
MethodA(subject, i);
MethodB(subject, i);
MethodC(subject, i);
}
}
// OK, OK, OK, OK, OK, OK, OK, OK, OK, OK
function MethodA(subject, iteration)
{
var myRegexp = new RegExp("5", "g");
var matches = myRegexp.exec(subject);
AddItem(matches ? "OK" : "no match", "listA");
}
// OK, OK, OK, OK, OK, OK, OK, OK, OK, OK
function MethodB(subject, iteration)
{
var myRegexp = /5/;
var matches = myRegexp.exec(subject);
AddItem(matches ? "OK" : "no match", "listB");
}
// OK, OK, OK, no match, OK, OK, OK, no match, OK, OK (in FireFox and Chrome, IE is fine)
function MethodC(subject, iteration) {
var myRegexp = /5/g;
var matches = myRegexp.exec(subject);
AddItem(matches ? "OK" : "no match", "listC");
}
function AddItem(itemText, listID) {
var li = document.createElement("li");
li.innerHTML = itemText;
document.getElementById(listID).appendChild(li);
}
</script>
</head>
<body onload="RunDemo()">
<h2>Method A</h2>
<ul id="listA"></ul>
<h2>Method B</h2>
<ul id="listB"></ul>
<h2>Method C</h2>
<ul id="listC"></ul>
</body>
</html>
函数RunDemo()
{
var subject=“01234 555 6789”;
对于(var i=1;i当我将变量名更改为myRegexp1、myRegexp2和myRegexp3时,仍然会发生这种情况,因此您的前提可能不正确。FWIW,Firefox 4 beta没有出现问题,只有Chrome。这在Mozilla Javascript参考中有所提及:
如果正则表达式使用
“g”标志,您可以使用exec方法
多次寻找连续的
在同一字符串中匹配。当
如果执行此操作,搜索将从
由指定的str的子字符串
正则表达式的lastIndex
财产
但我不明白为什么在离开MethodC后保留lastIndex属性
编辑:
我发现了这个bug,它似乎很好地描述了您在这里遇到的情况:Chrome(&FF)中的属性是:
但不是IE:
至于为什么会发生这种情况,我不确定。您可以使用
function MethodC(subject, iteration) {
var myRegexp = /5/g;
var matches = subject.match(myRegexp);
AddItem(matches ? "OK" : "no match", "listC");
}
V8和spidermonkey中的优化器在看到regex文本时创建一个regex对象并重用它
根据ECMA3,这是符合要求的行为,但在ECMA5中会变得不符合要求
7.8.5正则表达式文本
正则表达式文字是一个输入元素,当它被调用时,它被转换为一个RegExp对象(第15.10节)
已扫描。对象在包含程序或函数的评估开始之前创建。对象的评估
literal生成对该对象的引用;它不创建新对象
程序求值为正则表达式对象,即使两个文本
内容相同。新的RegExp(第15.10.4节)或调用
作为函数的RegExp构造函数(第15.10.3节)
ECMAScript语言规范第3版
与之相比:
7.8.5正则表达式文本
正则表达式文字是一个输入元素,每次
计算文本。程序中的两个正则表达式文本计算为
即使两个文本的内容相同,也不要将as==彼此进行比较。RegExp对象也可能
在运行时由新的RegExp(见15.10.4)或将RegExp构造函数作为函数调用(15.10.3)创建
ECMAScript语言规范第5版
以下是一些解决方法:
- 不要将
/g
标志与exec
一起使用
- 从RegExp构造函数而不是从RegExp文本创建RegExp
我认为,执行这两项操作中的一项或两项都可以解决问题。我并不是说正则表达式对象在不同的函数之间共享,而只是在对MethodC的函数调用之间共享。在输出“不匹配”之前输出的OK数等于“5”数主题中的字符。我怀疑它与第一次调用中的第一个匹配,然后在第二次调用中与下一个“5”匹配,等等。它似乎记得上一个匹配的位置,这对我来说很奇怪。嗯……你是说它记住了正则表达式的lastIndex属性吗?有多奇怪……最后一点就是我想找出的:)因为JavaScript函数只是另一个对象,在函数运行后正则表达式不会被重新创建“构造”。在方法A中,显式调用新方法,计算并构造一个新的正则表达式,然后将其分配给myRegexp变量(属性)。在方法B中,每次运行都会耗尽匹配项。在方法C中,JS引擎可以查看对myRegexp的分配,并说“是的,我已经得到了。”“直到匹配耗尽。(您可以在调试器中查看索引的运行情况——a和B在每次迭代中都命中6。)我不确定我添加到我的答案中的错误是否真的是造成这种情况的原因,因为它在几个月前就已经被修复了…可能还没有进入OP正在使用的任何版本中。Chrome在我上次检查时也做了同样的事情(我承认,最近并不是这样)。我怀疑在循环迭代中对regexp文本的缓存可能不正确。MDC提到了不需要在循环迭代中重新编译的regexp文本,但我原以为函数作用域会创建一个新实例。感谢您的解决方法。您能否提供一个链接来确认您关于重用RegEx的声明从文字创建的对象?当然,我更新了我的答案。看起来我的规格是向后的;第三版确实指定了这种行为,所以奇怪的交替匹配实际上是按照标准的…至少在ES5最终确定之前是这样的。