_.isEqualWith
的自定义比较功能进行斗争。我想要一个可以正常工作的函数:
const comparisonFunc = /* ...TBC... */
// Should be true:
_.isEqualWith({ a: undefined }, { }, comparisonFunc);
// Should still be false, as normal:
_.isEqualWith({ a: undefined }, { a: 123 }, comparisonFunc);
// Should still be false, as normal:
_.isEqualWith([undefined], [ ], comparisonFunc);
即对于比较中的任何对象(递归地),设置为
undefined
的属性应被视为不存在。
这并不像我想要的那么简单,但我找到了解决方案:
const comparisonFunc = (a, b) => {
if (_.isArray(a) || _.isArray(b)) return;
if (!_.isObject(a) || !_.isObject(b)) return;
if (!_.includes(a, undefined) && !_.includes(b, undefined)) return;
// Call recursively, after filtering all undefined properties
return _.isEqualWith(
_.omitBy(a, (value) => value === undefined),
_.omitBy(b, (value) => value === undefined),
comparisonFunc
);
}
// Should be true:
_.isEqualWith({ a: undefined }, { }, comparisonFunc); // = true
// Should still be false, as normal:
_.isEqualWith({ a: undefined }, { a: 123 }, comparisonFunc); // = false
// Should still be false, as normal:
_.isEqualWith([undefined], [ ], comparisonFunc); // = false
如果有人有更简单或更好的东西,我很乐意接受其他答案:-)
您可以检查是否是数组或对象并相应地过滤
undefined
成员,然后递归调用就是这样。
const comp = (a, b) => {
var A, B,
fn = v => !_.isUndefined(v),
filter = _.isArray(a) ? _.filter : _.pickBy;
if (_.isObject(a)) {
A = filter(a, fn)
B = filter(b, fn)
} else { return _.isEqual(a, b); }
if (_.keys(a).length === _.keys(A).length && _.keys(b).length === _.keys(B).length) {return}
return _.isEqualWith(A, B, comp);
};
var a1 = [10, 10, undefined, undefined, 10],
a2 = [undefined, undefined, 10, undefined, 10, undefined, 10],
o1 = {x: 10, y:undefined, z: 20, v: a1}
o2 = {x: 10, z: 20, v: a2};
console.log('a1 with a2: ', _.isEqualWith(a1, a2, comp));
console.log('o1 with o2: ', _.isEqualWith(o1, o2, comp));
console.log('a1 with o2: ', _.isEqualWith(a1, o2, comp));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
检查密钥长度和返回语句是为了确定我们是否必须在内部进行遍历(我们在上次迭代中删除了未定义的值),或者我们需要再次遍历它(因为我们在本次迭代中删除了未定义的值)
与 Tim Perry 的答案相同,仅使用 TypeScript 和
lodash/fp
function matchMissingWithUndefined(a: {}, b: {}) {
const hasUndefined = _.includes(undefined);
if (_.isPlainObject(a) && _.isPlainObject(b) && (hasUndefined(a) || hasUndefined(b))) {
const onlyDefined = _.omitBy((value) => value === undefined);
return _.isEqualWith(matchMissingWithUndefined, onlyDefined(a), onlyDefined(b));
}
}
_.isEqualWith(matchMissingWithUndefined, { a: undefined }, { }); // true
省略
null
值后,我们应该以某种方式绕过对 customizer
的初始调用,而不检查该对象是否再次具有 includes
null
值。
我为此目的发明了某种不错的自行车:
const compareWithoutNullProperties = (a: any, b: any) =>
isPlainObject(a) && isPlainObject(b)
? isEqualWith(
omitBy(a, (value) => value == null),
omitBy(b, (value) => value == null),
(a: any, b: any, key?: number | string | symbol): boolean | undefined =>
// Next initial call should be ignored.
key != null ? compareWithoutNullProperties(a, b) : undefined,
)
: undefined;
const isEqualWithoutNullProperties = (a: any, b: any) =>
isEqualWith(a, b, compareWithoutNullProperties);
测试返回
true
:
isEqualWithoutNullProperties({ a: undefined }, {});
isEqualWithoutNullProperties({ a: null }, {});
isEqualWithoutNullProperties([{ a: undefined }], [{}]);
isEqualWithoutNullProperties([{ a: null }], [{}]);
isEqualWithoutNullProperties({ a: { a: undefined } }, { a: {} });
isEqualWithoutNullProperties({ a: { a: null } }, { a: {} });
isEqualWithoutNullProperties({ a: [{ a: undefined }] }, { a: [{}] });
isEqualWithoutNullProperties({ a: [{ a: null }] }, { a: [{}] });
测试返回
false
:
isEqualWithoutNullProperties([undefined], []);
isEqualWithoutNullProperties([null], []);
isEqualWithoutNullProperties([undefined], [1]);
isEqualWithoutNullProperties([null], [1]);
isEqualWithoutNullProperties({ a: undefined }, { a: 1 });
isEqualWithoutNullProperties({ a: null }, { a: 1 });
isEqualWithoutNullProperties([{ a: undefined }], [{ a: 1 }]);
isEqualWithoutNullProperties([{ a: null }], [{ a: 1 }]);
isEqualWithoutNullProperties({ a: { a: undefined } }, { a: { a: 1 } });
isEqualWithoutNullProperties({ a: { a: null } }, { a: { a: 1 } });
isEqualWithoutNullProperties({ a: [{ a: undefined }] }, { a: [{ a: 1 }] });
isEqualWithoutNullProperties({ a: [{ a: null }] }, { a: [{ a: 1 }] });
我们可以在比较之前简单地预处理对象
_.isEqual(_.omitBy({ a: undefined }, _.isNil), _.omitBy({}, _.isNil)); // true
_.isEqual(_.omitBy({ a: undefined }, _.isNil), _.omitBy({ a: 123 }, _.isNil)); // false