Open HeftyKoo opened 4 years ago
尝试解释一下二分中位值特殊情况为什么不加 NaN和undefined,个人认为加上是比较好理解的,但是不加在效果上其实是一样的。因为如果computed的值为NaN || undefined,会进入下一个条件判断,也就是比较值,在值的比较中,undefined会被转换为NaN,而 对NaN的所有比较返回值都是false,也就是setLow永远为false,而如果computed值为 null | Symbol,null在进行值转换时会变成0,Symbol会直接报错,因此必须单独拿出来判断。如有不对,欢迎指正!:smile:
本文为读 lodash 源码的第八十篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
依赖
《lodash源码分析之isSymbol》
源码分析
baseSortedIndexBy
是实现sortedIndexBy
和sortedLastIndexBy
的基础方法。其作用是找出,指定的
value
在一个已经排好序的数组array
中,应该插入的位置,这样就算这个value
插入到这个位置,原来的数组的排序不会打乱。因为同时要支持
baseSortedIndexBy
和sortedLastIndexBy
,也就是要支持插在前面和插在后面两种情况,baseSortedIndexBy
比这两个函数需要多一个参数来做标识,这个参数就是retHighest
。具体源码如下:
数组长度最大值
数组长度最大值
MAX_ARRAY_LENGTH
为4294967295
,因为value
需要插入,因此最大安全的插入位置为MAX_ARRAY_LENGTH - 1
处。处理边界情况
这段处理的是数组没传,或者数组传入为空的情况,这时,直接返回
0
。接下来就是使用二分查找的方式,来确定
value
最终要插入的位置。value 取值
在比较的时候,可能并不是使用传入的
value
来比较的,需要调用iteratee
迭代器来取得value
的计算值,在二分查找的时候,也会调用iteratee
来计算比较的值。因为数组中包含的可能不一定为数字,例如传入一个对象
{name: 'test', number: 1}
,其实number
是排序数组的主键,调用iteratee
时,应该返回数字1
来进行比较。处理value为NaN的情况
setLow
表示排除低位,每次二分后,如果setLow
为true
,表示结果需要在高位的那半数组中查找。如果
value
传入的为NaN
值,如果retHighest
传入的为true
,则setLow
也为true
,如果在当前二分的过程中,没有遇到NaN
值,即othIsReflexive
,setLow
也为true
,即将低位数组舍弃,继续向高位找value
的位置。retHighest
很容易理解,例如数组[1,2,3,4]
,如果传入retHightest
为true
,value
为NaN
,则一直向高位查找,因为每次二分时,低位都不符合,最后返回的是高位high
,这个值为array.length
,也即是4
,表示value
。但是对于
othIsReflexive
这个条件我是有疑惑的,因为如果是这样的数组[NaN, 1, 2, 3]
,retHightest
传入的是false
,但是最终的结果返回的会是4
,因为在第一次二分时,computed
的值为2
,也即othIsReflexive
为true
,直接将低位舍弃了,继续向高位查找时,othIsReflexive
也都为true
,直到数组查找完毕,最后返回的也就是4
了,但是我本来期望它返回0
才对。处理undefined的情况
这个逻辑其实和
NaN
的处理有点类似,othIsReflexive
表示当前二分位的值不为NaN
,如果有NaN
值,则舍弃高位,向低位查找插入的位置。然后判断
retHighest
是否为true
,如果是,则向高位查找;如果当前二分位的值有定义,也继续向高位查找。处理null的情况
处理
null
的情况和处理undefined
的情况是类似的。在处理
null
时,如果当前二分位的值为NaN
或者为undefined
,则向低位查找。如果都不是,则判断
retHighest
是否为true
,如果为true
,直接向高位查找;如果当前二分位的值不为null
,也是继续向高位查找。处理symbol的情况
为什么要处理
symbol
呢,因为symbol
是不能隐式转换成number
,也即没办法比较大小。symbol
的处理和前面几种类型的逻辑是差不多的,只不过在排除低位时,将NaN
,undefined
和null
都考虑上了。这样的目的也很明显,因为
symbol
毕竟是已经定义了的,不应该排在NaN
,undefined
或者null
的前面。处理二分中位值的特殊情况
在考虑完
value
的以上的情况后,此时的value
是不为NaN
、undefined
、null
和symbol
,此时如果当前二分中位值为null
或者symbol
,则向低位数组查找value
的位置。这块有点不是很明白,如果逻辑一致,中位值为
NaN
或者为undefined
时,也应该向下查找才对。直接比较大小的情况
处理完特殊情况后,就直接用中位值
computed
和value
进行比较,如果中位值比value
小,表示value
的位置应该在高位。如果
retHighest
有值,则在相等的情况下,也向高位继续找value
的位置。例如
[1,1,1,2]
,传入的value
为1
,在retHighest
为true
的情况下,返回的index
为3
,否则返回的index
为0
。License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面