function looseEqual(a, b) {
  if (a === b) {
    return true
  }
  let aValidType = isDate(a)
  let bValidType = isDate(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType ? a.getTime() === b.getTime() : false
  }
  aValidType = isArray(a)
  bValidType = isArray(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType
      ? a.length === b.length && a.every((e, i) => looseEqual(e, b[i]))
      : false
  }
  aValidType = isObject(a)
  bValidType = isObject(b)
  if (aValidType || bValidType) {
    /* istanbul ignore if: this if will probably never be called */
    if (!aValidType || !bValidType) {
      return false
    }
    const aKeysCount = keys(a).length
    const bKeysCount = keys(b).length
    if (aKeysCount !== bKeysCount) {
      return false
    }
    for (const key in a) {
      const aHasKey = a.hasOwnProperty(key)
      const bHasKey = b.hasOwnProperty(key)
      if ((aHasKey && !bHasKey) || (!aHasKey && bHasKey) || !looseEqual(a[key], b[key])) {
        return false
      }
    }
  }
  return String(a) === String(b)
}
/**
 * Check if two values are loosely equal - that is,
 * if they are plain objects, do they have the same shape?
 * Returns boolean true or false
 */
Check if two values are loosely equal - that is,
if they are plain objects, do they have the same shape.
Returns boolean true or false
Check if two values are loosely equal - that is if they are plain objects do they have the same shape . Returns boolean true or false
function looseEqual(a, b) {
  if (a === b) {
    return true
  }
  let aValidType = isDate(a)
  let bValidType = isDate(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType ? a.getTime() === b.getTime() : false
  }
  aValidType = isArray(a)
  bValidType = isArray(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType
      ? a.length === b.length && a.every((e, i) => looseEqual(e, b[i]))
      : false
  }
  aValidType = isObject(a)
  bValidType = isObject(b)
  if (aValidType || bValidType) {
    if (!aValidType || !bValidType) {
      return false
    }
    const aKeysCount = keys(a).length
    const bKeysCount = keys(b).length
    if (aKeysCount !== bKeysCount) {
      return false
    }
    for (const key in a) {
      const aHasKey = a.hasOwnProperty(key)
      const bHasKey = b.hasOwnProperty(key)
      if ((aHasKey && !bHasKey) || (!aHasKey && bHasKey) || !looseEqual(a[key], b[key])) {
        return false
      }
    }
  }
  return String(a) === String(b)
}
function looseEqual ( a , b ) { if ( a === b ) { return true } let aValidType = isDate ( a ) let bValidType = isDate ( b ) if ( aValidType || bValidType ) { return aValidType && bValidType ? a . getTime ( ) === b . getTime ( ) : false } aValidType = isArray ( a ) bValidType = isArray ( b ) if ( aValidType || bValidType ) { return aValidType && bValidType ? a . length === b . length && a . every ( ( e , i ) => looseEqual ( e , b [ i ] ) ) : false } aValidType = isObject ( a ) bValidType = isObject ( b ) if ( aValidType || bValidType ) { if ( ! aValidType || ! bValidType ) { return false } const aKeysCount = keys ( a ) . length const bKeysCount = keys ( b ) . length if ( aKeysCount !== bKeysCount ) { return false } for ( const key in a ) { const aHasKey = a . hasOwnProperty ( key ) const bHasKey = b . hasOwnProperty ( key ) if ( ( aHasKey && ! bHasKey ) || ( ! aHasKey && bHasKey ) || ! looseEqual ( a [ key ] , b [ key ] ) ) { return false } } } return String ( a ) === String ( b ) }
Check if two values are loosely equal - that is,
 if they are plain objects, do they have the same shape?
Check if two values are loosely equal - that is if they are plain objects do they have the same shape?
/* istanbul ignore if: this if will probably never be called */