关于Underscore.js中_.uniq与_.groupBy函数的使用疑问
嘿,我来帮你把这个问题掰明白!你遇到的情况其实是因为**.uniq和.groupBy对“按属性操作”的支持方式完全不同**,咱们一步步拆解:
先说说为什么_.groupBy能成功
Underscore的_.groupBy函数特别贴心,当你给它传一个字符串(比如'name')作为第二个参数时,它会自动把这个字符串当成对象的属性名,遍历数组里的每个对象,提取对应属性的值作为分组的key。举个例子:
const arr = [{name: 'Alice', age: 25}, {name: 'Bob', age: 30}, {name: 'Alice', age: 25}]; const grouped = _.groupBy(arr, 'name'); // 结果会是 { Alice: [两个Alice对象], Bob: [Bob对象] }
内部逻辑相当于帮你写了item => item.name这个迭代器,所以对对象数组的分组操作非常顺手。
再聊聊为什么_.uniq会失败
这就是关键坑点了!Underscore的_.uniq默认是用**严格相等(===)**来判断元素是否重复的。对于对象来说,哪怕两个对象的age属性完全一样,它们也是内存里的不同引用,所以默认的_.uniq根本不会把它们当成重复项。
更重要的是:Underscore的_.uniq不支持直接传属性名字符串作为参数!你可能以为和_.groupBy一样传'age'就行,但其实_.uniq的参数结构是这样的:
_.uniq(array, [isSorted], [iteratee])
第二个参数是布尔值isSorted(用来告诉函数数组是否已排序,优化性能),第三个参数才是迭代器函数,用来提取要比较的值。如果你直接写_.uniq(arr, 'age'),'age'会被强制转为布尔值true,相当于开启了排序优化,但完全没用到age属性来做比较——这就是你去重失败的原因!
正确的_.uniq按属性去重写法
要实现按age字段去重,你需要显式传入一个迭代器函数,告诉_.uniq要基于哪个属性做比较:
const arr = [{name: 'Alice', age: 25}, {name: 'Bob', age: 25}, {name: 'Charlie', age: 30}]; // 写法1:直接写箭头函数 const uniqByAge = _.uniq(arr, false, item => item.age); // 写法2:用Underscore的_.property简化(更优雅) const uniqByAge = _.uniq(arr, false, _.property('age'));
这两种写法都会让_.uniq提取每个对象的age值来做比较,这样就能得到按age去重后的数组了。
最后总结一下
_.groupBy支持直接传属性名字符串,内部会自动处理为属性访问器_.uniq默认用严格相等比较元素,且必须通过第三个参数的迭代器函数来指定按属性去重,不能直接传字符串
内容的提问来源于stack exchange,提问作者amu61

