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.length0 时,表示 source 是一个空对象。

如果 object == null ,表示 objectnull 或者 undefined,此时,如果 matchData.length0 ,则返回的结果为 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
  }
}

遍历 matchDatadata[2]true 时,也即可使用 === 比较,并且 noCustomizertrue ,也即没有传入自定义比较函数时,使用以下的方式先进行检测:

data[1] !== object[data[0]]

其中 data[1]valuedata[0]key ,这句的意思是,如果 source 中对应 keyvalueobject 对应 keyvalue 不相等,则 object 是不包含 source 的。

否则,在这步,再使用以下的方式检测:

!(data[0] in object)

即存在于 source 中的 keyobject 中不存在,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,再排除 keysource 上,但不在 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)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面

results matching ""

    No results matching ""