lodash源码分析之baseIsMatch
本文为读 lodash 源码的第二百二十七篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
依赖
import Stack from './Stack.js'
import baseIsEqual from './baseIsEqual.js'
《lodash源码分析之Stack》 《lodash源码分析之baseIsEqual》
源码分析
baseIsMatch 是实现 isMatch 方法的基础,isMath 的大部分逻辑由 baseIsMath 来实现。
baseIsMath 用来检测 object 是否包含 source ,即 object 要包含 source 的所有属性,并且对应属性的值相等。
一些常量
const COMPARE_PARTIAL_FLAG = 1
const COMPARE_UNORDERED_FLAG = 2
COMPARE_PARTIAL_FLAG 表示开启局部比较,COMPARE_UNORDERED_FLAG 表示开启无序比较。
空值处理
let index = matchData.length
const length = index
const noCustomizer = !customizer
if (object == null) {
return !length
}
matchData 在上篇文章《lodash源码分析之getMatchData》已经有过分析,是 source 的 [key, value, isStrictComparableFlag] 集合。
因此 matchData.length 为 0 时,表示 source 是一个空对象。
如果 object == null ,表示 object 为 null 或者 undefined,此时,如果 matchData.length 为 0 ,则返回的结果为 true ,否则为 false。
可全等比较值的比较
let data
let result
object = Object(object)
while (index--) {
data = matchData[index]
if ((noCustomizer && data[2])
? data[1] !== object[data[0]]
: !(data[0] in object)
) {
return false
}
}
遍历 matchData,data[2] 为 true 时,也即可使用 === 比较,并且 noCustomizer 为 true ,也即没有传入自定义比较函数时,使用以下的方式先进行检测:
data[1] !== object[data[0]]
其中 data[1] 为 value ,data[0] 为 key ,这句的意思是,如果 source 中对应 key 的 value 和 object 对应 key 的 value 不相等,则 object 是不包含 source 的。
否则,在这步,再使用以下的方式检测:
!(data[0] in object)
即存在于 source 中的 key 在 object 中不存在,object 也是不包含 source 的。
这两个比较都没有涉及到 object 包含 source 的情况,之所以要分开处理,是出于性能的考虑,只通过一层比较就可以排除掉一些不包含的情况。
处理object上不存在key的情况
while (++index < length) {
data = matchData[index]
const key = data[0]
const objValue = object[key]
const srcValue = data[1]
if (noCustomizer && data[2]) {
if (objValue === undefined && !(key in object)) {
return false
}
} else {
...
}
}
接下来再遍历 matchData,再排除 key 在 source 上,但不在 object 上的情况。
在上面满足 noCustomizer && data[2] 这个条件时,使用的是 === 比较,如果 key 不在 object 上拿到的值会是 undefined,如果 source 的值恰好也是 undefined,得到的结果会是 true 。
因此这里使用 key in object 来检测,如果不在 object 上,则可以直接返回 false 。
自定义比较函数
while (++index < length) {
...
if (noCustomizer && data[2]) {
...
} else {
const stack = new Stack
if (customizer) {
result = customizer(objValue, srcValue, key, object, source, stack)
}
...
}
}
如果传入了自定义比较函数 customizer ,则直接调用 customizer 函数得出结果。
baseIsEqual比较值是否相等
if (!(result === undefined
? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
: result
)) {
return false
}
如果没有传入自定义比较函数,或者自定义比较函数返回的结果是 undefined ,则使用 baseIsEqual 来比较两者的值是否相等。
要注意这里 bitmask 传入的是局部比较和无序比较,因为是检测 object 是否包含 source ,使用局部比较即可。
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面