# isEqualWith

# Description

这个方法类似 isEqual。 除了它接受一个 customizer 用来定制比较值。 如果 customizer 返回 undefined 将会比较处理方法代替。 customizer 会传入 6 个参数:(objValue, othValue [, index|key, object, other, stack]

# Params

(value, other, customizer)

# Return

Boolean

# Depend

import baseIsEqual from './.internal/baseIsEqual.js'

baseIsEqual 源码分析

# Code

function isEqualWith(value, other, customizer) {
  customizer = typeof customizer === 'function' ? customizer : undefined
  const result = customizer ? customizer(value, other) : undefined
  return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result
}

# Analyze

对于 customizer 参数做了处理,如果 customizer 不是一个 function 类型,则将其置为 undefined

根据 customizer 是否为真值,得到 result 的值,如果 customizer 是一个 函数,则调用 customizer 方法对 value 和 other 进行处理, 否则 result 为 undefined

最终 如果 result 是 undefined ,则使用 baseIsEqual 进行比较,否则 返回 !!result ,也就是 使用 双非操作符返回 布尔值

# Remark

这里对于 customizer 的方法处理有点问题,假设

const a = {
  a: 1
}

const b = {
  a: 2
}

console.log(isEqualWith(a, b, (x, y) => {
  if (x.a <= y.a) {
    --y.a
    return
  }
  return y.a
}))

如果我们传入这样的值,按照道理来说,他们应当是不想等的,但是 对于 isEqualWith 方法,这里 customizer 方法 其实处理了两遍,导致他们是相等的 返回了 true

首先 在 isEqualWith 方法内部

  const result = customizer ? customizer(value, other) : undefined

这一点,就执行了 customizer 方法

然后后续调用 baseIsEqual 方法时,对于 customizer 方法,又执行了一次,导致返回了错误的结果

在 isEqualWith 调用 customizer 时,应当使用 cloneDeep 对 value 和 other 进行处理

对于上述代码,在不使用 cloneDeep 时,返回 true,但是如果使用 cloneDeep 处理之后,返回 false

# Example

const a = {
  a: 1
}

const b = {
  a: 2
}

const c = {
  a: 1
}

const d = {
  a: 2
}
console.log(isEqualWith(c, d)) // false

console.log(isEqualWith(a, b, (x, y) => {
  if (x.a <= y.a) {
    --y.a
    return
  }
  return y.a
})) // 使用 cloneDeep 应当返回 false