JavaScript在函数中编译正则表达式文字的频率是多少?

时间:2012-01-11 04:08:38

标签: javascript regex

鉴于此功能:

function doThing(values,things){
  var thatRegex = /^http:\/\//i; // is this created once or on every execution?
  if (values.match(thatRegex)) return values;
  return things;
}

JavaScript引擎多久创建一次正则表达式?每次执行一次或每页一次加载/脚本解析?

为了防止不必要的回答或评论,我个人倾向于将正则表达式置于函数之外,而不是在函数内部。问题是关于语言的行为,因为我不知道在哪里查看,或者这是引擎问题。


编辑:

我被提醒我没有提到这将在循环中使用。道歉:

var newList = [];
foreach(item1 in ListOfItems1){ 
  foreach(item2 in ListOfItems2){ 
    newList.push(doThing(item1, item2));
  }
}

因此,假设它将在循环中多次使用,那么在函数外部定义正则表达式是有意义的,但这就是理念。

还注意到脚本是相当通用化的,目的只是检查正则表达式创建的行为和成本

4 个答案:

答案 0 :(得分:13)

来自正则表达式的Mozilla's JavaScript Guide

  

正则表达式文字在评估脚本时提供正则表达式的编译。当正则表达式保持不变时,请使用它以获得更好的性能。

来自ECMA-262 spec,§7.8.5正则表达式文字:

  

正则表达式文字是一个输入元素,每次评估文字时都会转换为RegExp对象(见15.10)。

换句话说,当它被评估为首先解析脚本时,它被编译一次。

值得注意的是,从ES5规范来看,两个文字将编译为 RegExp的两个不同实例,即使文字本身是相同。因此,如果给定的文字在您的脚本中出现两次,它将被编译两次,到两个不同的实例:

  

程序中的两个正则表达式文字计算为正则表达式对象,即使两个文字的内容相同,也不会相互比较为===。

     

...

     

...每次计算文字时,都会创建一个新对象,就像表达式new RegExp(Pattern, Flags)一样,其中RegExp是具有该名称的标准内置构造函数。

答案 1 :(得分:6)

提供的答案并没有清楚地区分幕后的两个不同过程:正则表达式编译正则表达式对象创建,同时点击regexp对象创建表达式。

是的,使用regexp文字语法,您可以获得一次正则表达式编译的性能优势。

但是如果您的代码在ES5 +环境中执行,每次代码路径都进入示例中的doThing()函数时,它实际上会创建一个新的RegExp对象,但是,无需一次又一次地编译正则表达式。

在ES5中,每当代码路径到达通过文字创建正则表达式的表达式时,文字语法都会生成一个新的RegExp对象:

function getRE() {
    var re = /[a-z]/;
    re.foo = "bar";
    return re;
}

var reg = getRE(),
    re2 = getRE();

console.log(reg === re2); // false
reg.foo = "baz";
console.log(re2.foo); // "bar"

要从实际数字的角度说明上述陈述,请查看此jsperfstoredRegExpinlineRegExp次测试之间的效果差异。

浏览器之间的

storedRegExpinlineRegExp快5到20% - 每次创建(和垃圾回收)新RegExp对象的开销。

<强> Conslusion:
如果您正在大量使用文字正则表达式,请考虑将它们缓存在需要它们的范围之外,这样它们不仅可以编译一次,而且它们的实际正则表达式对象也会被创建一次。

答案 2 :(得分:5)

每次调用函数时都会编译正则表达式,如果它不是字面形式
由于您以字面形式包含它,因此您无需担心。

以下是websina.com的引用:

  

正则表达式文字在评估脚本时提供正则表达式的编译。当正则表达式保持不变时,使用它来获得更好的性能。

     

调用RegExp对象的构造函数,如下所示:
  re = new RegExp("ab+c")

     

使用构造函数提供正则表达式的运行时编译。当您知道正则表达式模式将要更改时,或者您不知道该模式并从其他源(例如用户输入)获取该模式时,请使用构造函数。

答案 3 :(得分:5)

javascript中有两个“正则表达式”类型对象。 Regular expression instances和RegExp对象。

此外,有两种方法可以创建正则表达式实例:

  1. 使用/ regex / syntax和
  2. 使用新的RegExp('regex');
  3. 每次都会创建新的正则表达式实例。

    但是只有一个全局的RegExp对象。

    var input = 'abcdef';
    var r1 = /(abc)/;
    var r2 = /(def)/;
    r1.exec(input);
    alert(RegExp.$1); //outputs 'abc'
    r2.exec(input);
    alert(RegExp.$1); //outputs 'def'
    

    在使用语法1

    时加载脚本时编译实际模式
      

    模式参数在使用前编译为内部格式。对于语法1,在加载脚本时编译模式。对于语法2,模式在使用之前编译,或者在调用编译方法时编译。

    但是你仍然可以在每个方法调用时获得不同的正则表达式实例。在chrome vs firefox中测试

    function testregex() {
        var localreg = /abc/;
        if (testregex.reg != null){
            alert(localreg === testregex.reg);
        };
        testregex.reg = localreg;
    }
    testregex();
    testregex();
    

    这是非常小的开销,但是如果你想要一个正则表达式,最安全的只是在你的函数中创建一个 实例