<script type="text/javascript"> function doRex(){ var example = "J'adore Firefox!"; // I like Firefox! var RE = /Fire/g; var result = RE.exec(example); if(result) alert("マッチ: " + result + "¥nlastIndex: " + RE.lastIndex); else alert("マッチしません!:" + "¥nlastIndex: " + RE.lastIndex); } </script> <button onclick="doRex();"> 実 行 1 </button>
上のdoRex()関数を実行すると、最初ボタンを押したときはちゃんとマッチしますが、2回目にボタンを押したときの結果がブラウザで異なります。Firefox3.0.7, Chrome1.0, Opera9.64では、「マッチしない」、IE6-8とSafari4 public betaでは、マッチして1回目と同じ結果です。なぜ、こういうことになるかというと、lastIndex絡みです。1回目の実行に対して、lastIndexの値が保持されているからです。2回目の実行で、マッチしないとなると、RE.lastIndexはまた0に戻るので、3回目の結果は初回と同じく「マッチ」です。
でも、疑問なのが、doRex()という関数の中で定義したローカルな変数だから、doRex()を実行する度に、lastIndexの値はリセットされるのが正しい気もするんだけどなぁ。doRex()の中ではなく、グローバルな空間で同様のことをやれば、SafariもIEも2回目は「マッチしない」となり、これは納得できる挙動なんですが。
では、このブラウザ間の差異をなくすにはどうするか?ひとつは、RE.exec(example) した後に、RE.lastIndex = 0; // 値をリセットという記述を加えて、明示的にlastIndexを元に戻す方法。もうひとつは、new演算子を使う方法です。これなら、どのブラウザでも同じ挙動、何度ボタンを押しても、「マッチ」となります。new RegExp("foo", "g") と /foo/g って同じと思っていたんだけど。
<script type="text/javascript"> function doRex2(){ var example = "J'adore Firefox!"; // I like Firefox! var RE2 = new RegExp("Fire", "g"); // new演算子を使用する var result2 = RE2.exec(example); if(result2) alert("マッチ: " + result2 + "¥nlastIndex: " + RE2.lastIndex); else alert("マッチしません!:" + "¥nlastIndex: " + RE2.lastIndex); } </script> <button onclick="doRex2();"> 実 行 2 </button>
上のコードであれば、ブラウザ間の差異がない。
でも、Safari/IE と Firefox/Chrome/Opera、どっちが正しい挙動なんだろうな。今イチ、すっきりしないです。
http://mayokara.info/deadspace/log/d200901.html
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/7_Lexical_Conventions.html#section-7.8.5
などにちょっと書いてありますけど、正規表現リテラルの仕様的には doRex 関数を最初に評価した時点で /Fire/ リテラルにオブジェクトが割り当てられて、RE 変数にはそれへの参照が入るそうです。doRex() を何度読んでも doRex の内部的なハッシュテーブルが変わらない限りは参照は変わらないはずなので、 RE 変数は同じものを差すということじゃないですかね。
たぶん仕様では Firefox/Chrome/Opera が正しいと思いますけど、詳しくは知りません。