雖然說寫了很多 JavaScript,但是還真的是頭一次遇到 global
的問題。其實也不是什麼問題,只是對於這個物件的不熟悉,所以覺得他是一個 Bug,後來才發現他是一個 Feature。
RegExp
在開始之前,我們可以先參考一下 MDN 的文件,
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions
然後可以看一下關於 Advanced Searching With Flags 的區段,在正規表達式的規則中,MDN 提出 JavaScript 有四種 Flags 可以使用,
g
全域搜尋i
不區分大小寫m
多行搜尋y
從指定的位置開始搜尋
然後其實偷看一下 RegExp
這個元件,他還會有 unicode
與 dotAll
這兩個 Flag 可以使用,分別是,
u
使用 Unicode 的功能搜尋s
代表dotAll
,是一個新的提案,代表任意單一字元(包含換行)
先說踩到的雷
應該說是一個 Feature!由於對於 RegExp 的不熟悉,加上又太習慣用 g
做全域搜尋,結果就造成了這次的慘案。舉一個類似的例子來看,
WTF!!!
對,我第一次的反應也是這樣。後來詳細查詢了 g
的參數之後,發現 RegExp 元件有一個東西很有趣,叫做 lastIndex
,而 g
這個參數完整的用意是,
對於所有的文字進行搜尋,找到比對結果後,會修改
lastIndex
到該結果的位置,下一次再次執行比對方法時,會從這個位置繼續開始往下找。
簡單的用圖片來解釋,
那中間的 false
到底是怎麼回事?依兆剛剛的說明,我們把整個步驟拆解出來看,他就會像是這樣,
const a = new RegExp('123', 'g');
const b = '123 456 789 123 456 789';
// 做第一次比對
a.test(b);
// 比對成功後,這個時候 lastIndex 會改變
console.log(a.lastIndex);
// lastIndex 會印出 3
// 做第二次比對,由於 lastIndex === 3,所以會從第 3 個位置開始往後搜尋
a.test(b);
// 比對成功後,這個時候 lastIndex 會改變
console.log(a.lastIndex);
// lastIndex 會印出 15
// 做第三次比對,由於 lastIndex === 15,所以會從第 15 個位置開始往後搜尋
a.test(b);
// 但是這次會比對失敗,因為第 15 個位置之後,找不到 123 了
// 這個時候 lastIndex 會自動歸零
console.log(a.lastIndex);
// lastIndex 會印出 0
這就是為何會出現一下子是 true
然後一下子是 false
的原因。之所以會覺得這個狀況有疑慮,是因為我製作一個很外層的變數,然後每次比對網址都呼叫該正規表達式物件來幫我做,但是,我又 沒有把 lastIndex
歸零,所以變成比對的情況會依照 呼叫的次數 產生預期外的結果。
對不起我錯了。
g
的用意是可以讓你找出全部的字串,而當你呼叫了 exec
或是 test
的時候,他會改變 lastIndex
,好讓你可以再做一次 exec
或 test
。所以,當你需要 重頭開始 的時候,請先把 lastIndex
歸零。
不歸零會怎樣?
當 a.test(b);
與 a.test(c);
距離很遠,或是根本在不同地方的時候(嘿嘿,請不要惡搞同事好嗎
'y' 參數
他跟 lastIndex
也是有關的,所以既然提到了就順便說一下。
但是!
這個參數有一個隱含的操作,就是在你的正規表達式當中,會幫你帶一個 ^
來做比對。換句話說,當你使用了這個參數,那麼每次比對都會強迫使用開頭比對來進行。舉例來說,
媽媽有說收工前不能罵髒話。
我剛剛提及了 每次比對都會強迫使用開頭比對來進行 。所以你第二次的比對會出現 false
是正確的,因為這個 test
會修改 lastIndex
的數值,當我做了第一次的 test
之後,那個 lastIndex
會變成 3。
接著,第二次的 test
會從 lastIndex = 3
的位置開始,然而 y
又是 強迫開頭比對 ,所以,當從第 3 個位置開始,比對 /^123/
的結果,就會是 false
。
那麼,你現在應該可以理解上圖,第一次的 test
為何為 false
了吧。那麼,你猜猜看上面的 lastIndex
最後會變成多少?
dotAll, 's' 參數
目前不確定瀏覽器支援程度,不過我在 Chrome DevTools 可以操作。他的意思是就是取代任何 單一 字節的文字,可以參考一下我上面的連結。
小結
沒事不要學人家寫什麼 JavaScript