擺了一個烏龍,本來要寫一段Javascript測試日期格式是否有效,用RegExp做檢測,結果誤加了一個g參數,發現好玩的事:

var s = "2009/03/10";
var regex=/^\d{4}[/]\d{2}[/]\d{2}$/g;
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));

以上程式碼,會出現一個true,一個false,再一個true,再一個false。如果拿掉g則可以如預期得到四個true。

如果我把測試放進迴圈中,如下:

for (var i=0; i<4; i++)
{
  var s = "2009/03/10";
  var regex=/^\d{4}[/]\d{2}[/]\d{2}$/g;
  alert(regex.test(s));
}

更有趣的事發生了,在IE/Safari中會得到四個true,而在Firefox/Chrome中則是true/false/true/false。

微軟技術的開發細節,盡在MSDN Library中,從沒費過心思去苦查狂找。但在Javascript上,雖然已用了多年,我卻連本書都沒買過,一向都是參考別人的Code亂抄一通、有了Google後更是順手一查,看到什麼吞什麼。RegExp的這個行為看來是By Design,但我不知要由何處查得權威性的定義。這回,決定再用一下Stackoverflow,不愧是國際級的平台,不到一個小時就有高手現身相救。

原來,使用g(Global)參數時,RegExp在做test()或exec()時,會保存一個指標lastIndex,記錄上次查詢結束的位置。所以,第一次test()後,lastIndex就指向字串結尾,第二次test()由結尾開始查,啥都查不到,就傳回false,然後再把lastIndex重設為0。由以下程式碼可以驗證:

var re = /a/g;
var s = "a";
document.write(re.lastIndex);
document.write(re.test(s))
document.write(re.lastIndex);
document.write(re.test(s))
document.write(re.lastIndex);

至於各瀏覽器的結果不同,我認為與Firefox/Chrome在重新宣告RegExp時,還沿用了前次的lastIndex有關(也許是基於效能,重覆使用物件)。利用以下程式,在IE可得00,而FF中則是01,故得證。

for (var i = 0; i < 2; i++)
{
  var re = /a/g;
  document.write(re.lastIndex);
  re.test("a");
}

這是一個標準的RTFM案例,不過我早先的困難在於無FM可R,感謝Stackoverflow的高手,回答問題時也順便指點我一個文件寶庫--Mozilla Developer Center,幾乎是網頁開發的四庫全書,當然不乏Javascript的完整參考,以後有問題就不用胡亂搜索了。


Comments

# by K

我就馬上測了多方面的測試 果然結果都非常有趣 順便提一個好玩無傷的Bug 不知道大大有沒有碰過 Visual Web Developer 2008 Express Edition 新增一個 js檔 而在js檔裡面 輸入 白 這時系統就會提示"無法完成動作" 我在2005 或 2003測都沒有.....XD

# by Igi

今天遇到了類似的問題 還以為自己迴圈寫錯 看了這篇文章測試後受益良多^^ 感激~

# by DonaldIsFreak

碰巧也遇到這樣的問題,也想貼到StackOverflow,果然~還是先Google就對了!感謝先進的文章,馬上就讓我找到解答…

Post a comment