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

jco*_*and 20 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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


编辑:

我被提醒我没有提到这将在循环中使用.我很抱歉:

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

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

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

Bol*_*ock 13

来自Mozilla的正则表达式JavaScript指南:

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

ECMA-262规范,§7.8.5正则表达式文字:

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

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

值得一提的还有,从ES5规范,这两个字符串将编译到两个不同的实例RegExp,即使文字本身是相同的.因此,如果给定的文字在您的脚本中出现两次,它将被编译两次,到两个不同的实例:

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

...

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

  • "每次评估文字"意味着每次评估发生时都会生成一个新实例.评估在运行时进行,而不是在解析期间进行.因此每次执行带有`RegExp`文字的函数时,如果使用或分配了`RegExp`文字,它将是一个新实例.我相信您正在考虑ES3行为,其中在解析期间创建新实例,并且每个文字**总是**评估到同一个对象(而不是评估到新对象).请参阅/sf/answers/3381767581/ (3认同)

Ale*_*mov 7

提供的答案没有清楚地区分场景背后的两个不同进程:regexp编译regexp对象创建在命中regexp对象创建表达式时.

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

但是如果您的代码在ES5 +环境中执行,那么每次代码路径进入doThing()示例中的函数时,它实际上都会创建一个新RegExp对象,而无需一次又一次地编译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"
Run Code Online (Sandbox Code Playgroud)

为了从实际数字的角度说明上述陈述,请查看此jsperf中测试storedRegExpinlineRegExp测试之间的性能差异.

storedRegExp跨浏览器的速度比inlineRegExp- RegExp每次创建(和垃圾收集)新对象的开销要快5到20% .

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

  • 您提到 ES5+ 在每次计算文字时都会创建一个新的 RegExp 对象。它在早期 Javascript 版本中的工作方式是否有所不同?请参阅/sf/ask/3243289941/,其中提问者引用了 5一年前的书,声称每次通过循环求值时,regexp 对象都会被重用。 (2认同)
  • 这是我见过的关于此主题的最佳答案。 (2认同)

Jos*_*ber 5

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

这是来自websina.com的报价:

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

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

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


jer*_*mel 5

javascript中有两个“正则表达式”类型的对象。 正则表达式实例和RegExp对象。

另外,有两种创建正则表达式实例的方法:

  1. 使用/ regex /语法和
  2. 使用新的RegExp('regex');

这些中的每一个每次都会创建一个新的正则表达式实例。

但是,只有一个全局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'
Run Code Online (Sandbox Code Playgroud)

使用语法1时,在加载脚本时会编译实际模式

使用之前,pattern参数将编译为内部格式。对于语法1,将在加载脚本时编译模式。对于语法2,模式是在使用之前或在调用compile方法时进行编译的。

但是您仍然可以在每个方法调用中获得不同的正则表达式实例。在Chrome和Firefox中测试

function testregex() {
    var localreg = /abc/;
    if (testregex.reg != null){
        alert(localreg === testregex.reg);
    };
    testregex.reg = localreg;
}
testregex();
testregex();
Run Code Online (Sandbox Code Playgroud)

这非常少,但是如果您只需要一个正则表达式,则最安全的做法是仅在函数外部创建一个实例