找回密码
 立即注册
首页 业界区 业界 数组去重的几种姿势

数组去重的几种姿势

啤愿 2025-9-26 10:47:13
上篇文章说到了引导式访问组件,其中有个扩展功能是是否强制以及是否第一次进行引导访问,这时候有个 guideKey 可以作为根据判断,那么存储拿取的时候就用到唯一值了,然后就有了这篇文章介绍的几种姿势,有深入哦~
背景

假设已经使用 guideKeyList 来记录已完成的引导步骤:
  1. let guideKeyList = uni.getStorageSync("guideKeyList") || [];
  2. guideKeyList.push(this.guideKey);
  3. guideKeyList = guideKeyList.unique(); // 自定义 unique 方法
  4. uni.setStorageSync("guideKeyList", guideKeyList);
复制代码
姿势一:原始写法(for 循环 + includes)
  1. Array.prototype.unique = function () {
  2.   let arr = [];
  3.   for (let i = 0; i < this.length; i++) {
  4.     if (!arr.includes(this[i])) {
  5.       arr.push(this[i]);
  6.     }
  7.   }
  8.   return arr;
  9. };
复制代码
优点:直观、好理解。
缺点:性能差(includes() 是 O(n))、代码冗长。
姿势二:原型扩展优化(使用 Object.create(null))
  1. Array.prototype.unique = function () {
  2.   const seen = Object.create(null);
  3.   const result = [];
  4.   for (let i = 0; i < this.length; i++) {
  5.     const item = this[i];
  6.     if (!seen[item + typeof item]) {
  7.       seen[item + typeof item] = true;
  8.       result.push(item);
  9.     }
  10.   }
  11.   return result;
  12. };
复制代码
优点:性能比 includes() 更优,避免 key 冲突。
缺点:污染 Array.prototype,多人协作项目慎用。
建议在文档中说明使用原型扩展的地方,防止冲突。
姿势三:推荐方式(使用 Set 封装函数)
  1. function uniqueArray(arr) {
  2.   return [...new Set(arr)];
  3. }
复制代码
优点:性能优秀,语义简洁,无副作用
缺点:IE 不支持 Set(已不再重要)。
如果不想污染原型链,这是最推荐的方式。
姿势四:filter + indexOf
  1. function uniqueArray(arr) {
  2.   return arr.filter((v, i, a) => a.indexOf(v) === i);
  3. }
复制代码
优点:不污染原型,兼容性好。
缺点:性能比 Set 略差,代码略冗余。
最终整合

在引导结束下使用:
  1. finish() {
  2.   // 可以单独拎出来在 main.ts or App.vue 等直接先实现一波,比较好看点,容易维护
  3.   Array.prototype.unique = function () {
  4.     const seen = Object.create(null);
  5.     const result = [];
  6.     for (let i = 0; i < this.length; i++) {
  7.       const item = this[i];
  8.       if (!seen[item + typeof item]) {
  9.         seen[item + typeof item] = true;
  10.         result.push(item);
  11.       }
  12.     }
  13.     return result;
  14.   };
  15.   this.visible = false
  16.   let guideKeyList = uni.getStorageSync('guideKeyList') || []
  17.   guideKeyList.push(this.guideKey)
  18.   guideKeyList = guideKeyList.unique() // 也可以替换为 Array.from(new Set(...))
  19.   uni.setStorageSync('guideKeyList', guideKeyList)
  20.   this.$emit('finish')
  21. }
复制代码
总结

方法是否污染原型性能可读性兼容性for + includes✅ 是❌ 差✅ 简单✅ 高Object.create✅ 是✅ 中✅ 清晰✅ 高Set❌ 否✅ 高✅ 极简❌ 旧 IE 不支持filter+indexOf❌ 否✅ 中✅ 普通✅ 高
如果是项目封装库或者多人协作,避免扩展原型链,推荐使用函数封装(如 uniqueArray(arr))。
拓展姿势:对象数组去重 & 深度去重

对象数组去重(根据 id 去重):
  1. function uniqueByKey(arr, key) {
  2.   const seen = new Set();
  3.   return arr.filter((item) => {
  4.     const val = item[key];
  5.     if (seen.has(val)) return false;
  6.     seen.add(val);
  7.     return true;
  8.   });
  9. }
  10. // 示例
  11. const arr = [
  12.   { id: 1, name: "A" },
  13.   { id: 2, name: "B" },
  14.   { id: 1, name: "C" },
  15. ];
  16. console.log(uniqueByKey(arr, "id"));
  17. // => [ { id: 1, name: 'A' }, { id: 2, name: 'B' } ]
复制代码
深度去重(针对嵌套对象结构):
  1. function deepUnique(arr) {
  2.   const seen = new Set();
  3.   return arr.filter((item) => {
  4.     const str = JSON.stringify(item);
  5.     if (seen.has(str)) return false;
  6.     seen.add(str);
  7.     return true;
  8.   });
  9. }
  10. // 示例:
  11. const nestedArr = [
  12.   { id: 1, data: { x: 1 } },
  13.   { id: 2, data: { x: 2 } },
  14.   { id: 1, data: { x: 1 } },
  15. ];
  16. console.log(deepUnique(nestedArr));
复制代码
注意:deepUnique 的比较是基于 JSON 字符串的浅层一致性,不适用于包含函数或 undefined 的复杂对象。
更进一步由大佬们来把姿势实现下吧:


  • 实现可配置的 unique(arr, { deep: true, key: 'id' }) 工具函数
  • 集成 lodash 或 Ramda 实现更强大的数据操作链
欢迎评论区继续探讨!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册