我悟出權力本來就是不講理的——蟑螂就是海米;也悟出要造反,內心必須強大到足以承受任何後果才行。
——北島《城門開》
本文為讀 lodash 原始碼的第十篇,後續文章會更新到這個倉庫中,歡迎 star:pocket-lodash
gitbook也會同步倉庫的更新,gitbook地址:pocket-lodash
作用與用法
baseFindIndex
是內部方法,其作用類似於ES6的 findIndex
,查詢符合條件的第一個元素的索引。
baseFindIndex
除了從前向後查詢外,還可以從後向前查詢。
用法如下:
baseFindIndex([3,1,2], function(val, index, array) {
return val > 1
}, 1) // 從前向後查詢,從索引1開始查詢,返回2
baseFindIndex([3,1,2], function(val, index, array) {
return val > 1
}, 1, true) // 從後向前查詢,從索引1開始查詢,返回3
複製程式碼
原始碼分析
function baseFindIndex(array, predicate, fromIndex, fromRight) {
const { length } = array
let index = fromIndex + (fromRight ? 1 : -1)
while ((fromRight ? index-- : ++index < length)) {
if (predicate(array[index], index, array)) {
return index
}
}
return -1
}
複製程式碼
這段程式碼再次展示了 lodash 的特點,短小精悍!
這次讀原始碼我們從裡往外看。
從程式碼中很容易看到,predicate
是傳遞進來的函式,在 baseFindIndex
呼叫該函式,如果返回的結果為真值,則中止查詢,返回索引。
運算子優先順序
我們再往外看,看看 while
的迴圈條件:
fromRight ? index-- : ++index < length
複製程式碼
現在問題來了,這個三元表示式有兩種可能,一種是:
(fromRight ? index-- : ++index) < length
複製程式碼
一種是:
fromRight ? index-- : (++index < length)
複製程式碼
究竟是那一種呢?這就要看運算子的優化級了,下面這個表是 MDN 上的截圖:
這個表將優化級劃分成了20個級別,數字越大,優化級越高。
從表中可以看到,比較運算子的優先順序為11,而三元表示式(條件運算子)的優化級為4,因此可以確定比較運算子的優先順序要比三元表示式的要高,迴圈條件其實等價於第二種寫法。
增減迷局
再往上看,可以看到這句程式碼:
let index = fromIndex + (fromRight ? 1 : -1)
複製程式碼
在向後查詢時, index
減少了1,而向前查詢時,index
增加了1,為什麼要這樣做呢?
再結合迴圈條件看下:
fromRight ? index-- : ++index < length
複製程式碼
在向前查詢時,使用的是 index--
表示式的運算結果,向後查詢時,使用的是 ++index < lenth
表示式的運算結果。
從上表中也可以看出字首自增比比較運算子的優化級要高。
字首自增返回的是自增後的結果,而在迴圈條件中就要將索引 index
增加1,這樣會忽略掉第一個需要遍歷的元素,作為補救,在開始遍歷前,需要將 index
減少1。
同理,在向前查詢時,需要將索引增加1,因為在遍歷開始時就已經將索引減少1。
那又為什麼向前查詢時用的是字尾自減,而不是用字首自減呢?
因為在向前查詢時,最終要查詢到陣列索引 0
的位置,字尾自減返回的是自減前的數值,因此當 index
為 1
時,自減後的 index
為 0
,但是在迴圈條件中依然拿 1
來進行判斷,所以使得索引 0
得以進入迴圈體。
關於字首自增/減和字尾自增/減的區別可以看《lodash原始碼分析之自減的兩種形式》。
參考
License
署名-非商業性使用-禁止演繹 4.0 國際 (CC BY-NC-ND 4.0)
最後,所有文章都會同步傳送到微信公眾號上,歡迎關注,歡迎提意見:
作者:對角另一面