故事的開始是這樣的:程序員
須要作的就是爲這個列表加上搜索功能。爲了更簡單的說明問題,這個問題最後就至關於對原始
name數組進行一次匹配過濾,因而想固然的有了相似下面的代碼:正則表達式
var ori=['李同窗1','李同窗2','李同窗3','劉同窗'] var searchText='李' var reg = new RegExp('.*'+searchText+'.*', 'g') var newArr = ori.filter(function(value) { return reg.test(value) }) console.log(newArr) //[ '李同窗1', '李同窗3' ]
這裏假設咱們的搜索字符串爲‘李’,預期過濾事後的新數組newArr應該爲['李同窗1','李同窗2','李同窗3'],可打印出來的結果只有2個,跳過了數組中的第二個元素。這裏隱藏了什麼問題?爲了說清楚這個問題,要從正則表達式自己的一個屬性lastIndex提及。數組
mdn的文檔說的很清楚,lastIndex是正則表達式一個可讀可寫的整形屬性,表示下次正則匹配的起始索引。只有在正則自己使用全局匹配 ‘g’ 時,該屬性纔會被設置而且起做用。且該屬性的設置遵循下面的規則:spa
若是 lastIndex 大於字符串的長度,則 regexp.test 和 regexp.exec 將會匹配失敗,而後 lastIndex 被設置爲 0。翻譯
若是 lastIndex 等於字符串的長度,且該正則表達式匹配空字符串,則該正則表達式匹配從 lastIndex 開始的字符串。code
若是 lastIndex 等於字符串的長度,且該正則表達式不匹配空字符串 ,則該正則表達式不匹配字符串,lastIndex 被重置爲 0.。regexp
不然,lastIndex 被設置爲緊隨最近一次成功匹配的下一個位置。blog
規則看的很暈,其實本身試一下就知道了。回顧上面的問題,咱們打印一下lastIndex屬性:索引
var ori=['李同窗1','李同窗2','李同窗3','劉同窗1'] var searchText='李' var reg = new RegExp('.*'+searchText+'.*','g') var newArr = ori.filter(function(value) { console.log(reg.lastIndex) return reg.test(value) }) console.log(newArr) //執行的結果爲 0 4 0 4 [ '李同窗1', '李同窗3' ]
由上面打印的結果,問題出在哪了已經很明顯了,對於數組中第二個元素的匹配,是從索引爲4開始(索引的結果還與 .* 默認的貪婪模式匹配有關,這裏不作贅述),這裏固然不匹配,符合上述第三個規則,知道了這一點,咱們就能夠很靈活的改正這個問題:ip
var ori=['李同窗1','李同窗2','李同窗3','劉同窗1'] var searchText='李' //最直接的就是取消正則的全局匹配標誌 var reg = new RegExp('.*'+searchText+'.*?') var newArr = ori.filter(function(value) { return reg.test(value) }) //把起始索引改回來 var reg = new RegExp('.*'+searchText+'.*?','g') var newArr = ori.filter(function(value) { reg.lastIndex=0 return reg.test(value) }) //還能夠忽略全部名稱的第一位進行匹配 var reg = new RegExp('.*'+searchText+'.*?','g') var newArr = ori.filter(function(value) { reg.lastIndex=1 return reg.test(value) })
最後一個細節,在非全局匹配模式下,lastIndex屬性是不起做用的,即便設置這個屬性值,匹配也會從起始位置開始。
其實解決這個問題,最開始的時候並無直擊問題的核心,只知道test()方法是返回一個布爾值,對lastIndex屬性也沒有太多瞭解,也就無法意識到這一層,但我仍是去mdn看了一下test()的文檔,默認看的中文版,很不幸中文版的翻譯裏恰好少了正則全局標誌下使用test()這一節,因而更堅決此方法不就是返回個布爾值的論斷。結果多繞了幾彎,一怒之下就跑去補充了mdn關於test()方法的中文翻譯。對於一個初級程序員的平常開發來講,不少時候遇到的‘意外’,都是相關內容知道的不全面,這時候參考文檔通常都是能夠發現問題。