正規表現リテラル(又はオブジェクト)をRegExpのコンストラクタに渡す時のフラグの扱い


case insensitiveなvalidation check用に用意していた正規表現リテラルを使ってglobalなreplaceをしたくなることが稀によくあります。

const re = /hoge/i;
.
.
.
re.test(str);
・
・
・
str2.replace(new RegExp(re, "g"), "huga");

こちらの記事にあるように、かつてはRegExpのコンストラクタにRegExpを渡すとエラーになっていたので、そもそも再利用はできなかったようです。

しかし、MDNにしれっと書かれてるように、ES6以降ではRegExpのコンストラクタは第一引数にRegExpを受け取ってくれるようです。

ECMAScript 6 より、第 1 引数が RegExp で第 2 引数に flags を指定する場合 (new RegExp(/ab+c/, 'i')) に TypeError が発生しません。代わりに、引数を元に新たな RegExp を生成します。

で、この場合最初のリテラルで指定したフラグと、後のコンストラクタに渡したフラグが違う時はどうなんのよ?っていうのを調べてみました。

実験環境

  • windows 10
  • node v8.12.0

実験結果

>node
> const re = /hoge/i
undefined
> const re2 = new RegExp("hoge", "i");
undefined

#re, re2ともにcase insensitiveな"hoge"にマッチするので"HOGE"が"huga"に置換される
> "HOGE hoge".replace(re, "huga");
'huga hoge'
> "HOGE hoge".replace(re2, "huga");
'huga hoge'

#"g"をつけて全体をreplaceしようとしても、"HOGE"は無視されて"hoge"だけ置換される
> "HOGE hoge".replace(new RegExp(re,"g"), "huga");
'HOGE huga'
> "HOGE hoge".replace(new RegExp(re2,"g"), "huga");
'HOGE huga'

#"gi"にすれば両方置換される
> "HOGE hoge".replace(new RegExp(re2,"gi"), "huga");
'huga huga'
> "HOGE hoge".replace(new RegExp(re,"gi"), "huga");
'huga huga'

まとめ

たまたま手元にあった環境で調べただけですが、リテラルだろうが正規表現オブジェクトだろうが、コンストラクタの第一引数に渡すと指定していたフラグは無かったことになるようなので、再指定が必要なようです。

おそらく、sourceプロパティの値を使ってるんでしょうね。