如何让含私有属性的类实例通过lodash isEqual比较时私有属性不同返回false
解决lodash isEqual无法区分私有属性不同的类实例问题
问题原因
你遇到的问题核心在于JavaScript的私有字段(#开头)是真正的私有,外部代码(包括lodash)无法直接访问这些字段。_.isEqual默认只会比较对象的可枚举公开属性,而你的Bobcat实例没有任何公开属性,所以lodash判定两个实例结构完全一致,返回true,哪怕它们的私有#items内容不同。
解决方案:外部实现自定义比较逻辑
按照要求,我们不在类内部添加任何方法,而是在外部封装一个自定义的比较函数,针对Bobcat实例做特殊处理,同时保留lodash对其他类型的默认比较能力。
思路是:利用Bobcat类提供的公开entries()方法,将私有#items的键值对转换为可比较的数组,再用lodash比较这些数组内容。
const _ = require('lodash') // 原Bobcat类保持不变 class Bobcat { #items; constructor() { this.#items = new Map() } set(key, value) { return this.#items.set(key, value) } get(key) { return this.#items.get(key) } has(key) { return this.#items.has(key) } delete(key) { return this.#items.delete(key) } clear() { this.#items.clear() } keys() { return this.#items.keys() } values() { return this.#items.values() } entries() { return this.#items.entries() } forEach(callbackFn, thisArg) { return this.#items.forEach(callbackFn, thisArg) } [Symbol.iterator]() { return this.#items[Symbol.iterator]() } } // 外部自定义比较函数 function customIsEqual(a, b) { const isBobcatA = a instanceof Bobcat const isBobcatB = b instanceof Bobcat // 两个都是Bobcat实例的情况 if (isBobcatA && isBobcatB) { // 把私有Map的键值对转为数组 const aEntries = Array.from(a.entries()) const bEntries = Array.from(b.entries()) // 比较键值对数组,同时保留对实例公开属性的比较(如果后续添加公开属性也能兼容) return _.isEqual(aEntries, bEntries) && _.isEqual(_.omit(a, []), _.omit(b, [])) } // 一个是Bobcat,一个不是,直接不相等 else if (isBobcatA !== isBobcatB) { return false } // 其他类型用lodash默认逻辑 return _.isEqual(a, b) } // 测试用例 const cat1 = new Bobcat() cat1.set('a', 1) const cat2 = new Bobcat() cat2.set('a', 2) const cat3 = new Bobcat() cat3.set('a', 1) console.log(customIsEqual(cat1, cat2)) // false(符合预期) console.log(customIsEqual(cat1, cat3)) // true(符合预期) console.log(customIsEqual({x:1}, {x:1})) // true(不影响其他类型比较)
说明
- 这个方案完全遵循要求:所有比较逻辑在类外部实现,没有修改
Bobcat类的内部代码,也没有添加类内方法或lodash专属的Symbol方法。 - 利用类本身提供的公开方法(
entries())间接获取私有属性的内容,既不破坏封装性,又能实现正确的比较。 - 保留了lodash对其他类型的默认比较逻辑,不会影响原有代码中对非
Bobcat实例的比较。
内容的提问来源于stack exchange,提问作者srgbnd
相关产品推荐
相关产品推荐

