Javascript文本regexp vs regexp对象,循环中的实例



我有以下两个js示例代码,一个使用文字regexp,另一个使用regexp对象:

"use strict";
var re;

// literal regexp
for(var i = 0; i<10; i++)
{
    re = /cat/g;
    console.log(re.test("catastrophe"));
}
// RegExp constructor
for(var i = 0; i<10;i++)
{
    re = new RegExp("cat", "g");
    console.log(re.test("catastrophe"));
}

有些书说,使用第一个例子"true"应该在每二次迭代时打印,因为使用字面表达式只会创建一个RegExp实例。因此,循环在第一次运行时找到子字符串"cat",而在第二次运行时,从剩下的地方继续,什么也没找到。第三次运行从头开始,以此类推。我已经测试过了,但似乎在两个例子中,我得到了10的计数。

你能解释一下为什么会这样吗?

第三版ECMAScript (JavaScript)规范允许缓存和重用正则表达式字面量,包括它们的状态,这导致了您提到的与第一个代码示例相关的"令人惊讶的"行为,它看起来确实应该在每个循环上创建一个新的正则表达式对象。大多数引擎都没有实现文字的缓存,这是一个非常糟糕的想法,第5版规范修复了它。

我相信所有用于缓存的现代引擎(主要是SpiderMonkey, Firefox的引擎)都相应地更新了。在您的两个示例中,每个迭代都会创建一个新的正则表达式。

Steven Levithan在这篇博客文章(就在最后)中的更多内容,以及规范附录E的第四段:

7.8.5:正则表达式字面量现在每次求值时返回一个唯一的对象。任何测试这些文字值的对象标识或对共享副作用敏感的程序都可以检测到这种更改。

在这两种情况下,您每次都通过for循环创建一个新的RegExp。用哪种方式声明RegExp并不重要——每次循环迭代时,它仍然会创建一个新的RegExp。因此,您将得到相同的行为。

现在,如果您在for循环之前初始化re变量,您将获得不同的行为,因为相同的RegExp对象的持久性以及它如何使用g标志。

最新更新