数组去重的几种姿势
<p>上篇文章说到了引导式访问组件,其中有个扩展功能是是否强制以及是否第一次进行引导访问,这时候有个 guideKey 可以作为根据判断,那么存储拿取的时候就用到唯一值了,然后就有了这篇文章介绍的几种姿势,有深入哦~</p><hr>
<h2 id="背景">背景</h2>
<p>假设已经使用 <code>guideKeyList</code> 来记录已完成的引导步骤:</p>
<pre><code class="language-js">let guideKeyList = uni.getStorageSync("guideKeyList") || [];
guideKeyList.push(this.guideKey);
guideKeyList = guideKeyList.unique(); // 自定义 unique 方法
uni.setStorageSync("guideKeyList", guideKeyList);
</code></pre>
<h2 id="姿势一原始写法for-循环--includes">姿势一:原始写法(for 循环 + includes)</h2>
<pre><code class="language-js">Array.prototype.unique = function () {
let arr = [];
for (let i = 0; i < this.length; i++) {
if (!arr.includes(this)) {
arr.push(this);
}
}
return arr;
};
</code></pre>
<p>优点:直观、好理解。<br>
缺点:性能差(<code>includes()</code> 是 O(n))、代码冗长。</p>
<hr>
<h2 id="姿势二原型扩展优化使用-objectcreatenull">姿势二:原型扩展优化(使用 <code>Object.create(null)</code>)</h2>
<pre><code class="language-js">Array.prototype.unique = function () {
const seen = Object.create(null);
const result = [];
for (let i = 0; i < this.length; i++) {
const item = this;
if (!seen) {
seen = true;
result.push(item);
}
}
return result;
};
</code></pre>
<p>优点:性能比 <code>includes()</code> 更优,避免 key 冲突。<br>
缺点:污染 <code>Array.prototype</code>,多人协作项目慎用。</p>
<blockquote>
<p>建议在<strong>文档中说明</strong>使用原型扩展的地方,防止冲突。</p>
</blockquote>
<hr>
<h2 id="姿势三推荐方式使用-set-封装函数">姿势三:推荐方式(使用 <code>Set</code> 封装函数)</h2>
<pre><code class="language-js">function uniqueArray(arr) {
return [...new Set(arr)];
}
</code></pre>
<p>优点:性能优秀,语义简洁,<strong>无副作用</strong>。<br>
缺点:IE 不支持 <code>Set</code>(已不再重要)。</p>
<p>如果不想污染原型链,这是最推荐的方式。</p>
<hr>
<h2 id="姿势四filter--indexof">姿势四:<code>filter + indexOf</code></h2>
<pre><code class="language-js">function uniqueArray(arr) {
return arr.filter((v, i, a) => a.indexOf(v) === i);
}
</code></pre>
<p>优点:不污染原型,兼容性好。<br>
缺点:性能比 <code>Set</code> 略差,代码略冗余。</p>
<hr>
<h2 id="最终整合">最终整合</h2>
<p>在引导结束下使用:</p>
<pre><code class="language-js">finish() {
// 可以单独拎出来在 main.ts or App.vue 等直接先实现一波,比较好看点,容易维护
Array.prototype.unique = function () {
const seen = Object.create(null);
const result = [];
for (let i = 0; i < this.length; i++) {
const item = this;
if (!seen) {
seen = true;
result.push(item);
}
}
return result;
};
this.visible = false
let guideKeyList = uni.getStorageSync('guideKeyList') || []
guideKeyList.push(this.guideKey)
guideKeyList = guideKeyList.unique() // 也可以替换为 Array.from(new Set(...))
uni.setStorageSync('guideKeyList', guideKeyList)
this.$emit('finish')
}
</code></pre>
<hr>
<h2 id="总结">总结</h2>
<table>
<thead>
<tr>
<th>方法</th>
<th>是否污染原型</th>
<th>性能</th>
<th>可读性</th>
<th>兼容性</th>
</tr>
</thead>
<tbody>
<tr>
<td>for + includes</td>
<td>✅ 是</td>
<td>❌ 差</td>
<td>✅ 简单</td>
<td>✅ 高</td>
</tr>
<tr>
<td><code>Object.create</code></td>
<td>✅ 是</td>
<td>✅ 中</td>
<td>✅ 清晰</td>
<td>✅ 高</td>
</tr>
<tr>
<td><code>Set</code></td>
<td>❌ 否</td>
<td>✅ 高</td>
<td>✅ 极简</td>
<td>❌ 旧 IE 不支持</td>
</tr>
<tr>
<td><code>filter+indexOf</code></td>
<td>❌ 否</td>
<td>✅ 中</td>
<td>✅ 普通</td>
<td>✅ 高</td>
</tr>
</tbody>
</table>
<blockquote>
<p>如果是项目封装库或者多人协作,<strong>避免扩展原型链</strong>,推荐使用函数封装(如 <code>uniqueArray(arr)</code>)。</p>
</blockquote>
<hr>
<h2 id="拓展姿势对象数组去重--深度去重">拓展姿势:对象数组去重 & 深度去重</h2>
<h3 id="对象数组去重根据-id-去重">对象数组去重(根据 <code>id</code> 去重):</h3>
<pre><code class="language-js">function uniqueByKey(arr, key) {
const seen = new Set();
return arr.filter((item) => {
const val = item;
if (seen.has(val)) return false;
seen.add(val);
return true;
});
}
// 示例
const arr = [
{ id: 1, name: "A" },
{ id: 2, name: "B" },
{ id: 1, name: "C" },
];
console.log(uniqueByKey(arr, "id"));
// => [ { id: 1, name: 'A' }, { id: 2, name: 'B' } ]
</code></pre>
<hr>
<h3 id="深度去重针对嵌套对象结构">深度去重(针对嵌套对象结构):</h3>
<pre><code class="language-js">function deepUnique(arr) {
const seen = new Set();
return arr.filter((item) => {
const str = JSON.stringify(item);
if (seen.has(str)) return false;
seen.add(str);
return true;
});
}
// 示例:
const nestedArr = [
{ id: 1, data: { x: 1 } },
{ id: 2, data: { x: 2 } },
{ id: 1, data: { x: 1 } },
];
console.log(deepUnique(nestedArr));
</code></pre>
<blockquote>
<p>注意:<code>deepUnique</code> 的比较是基于 JSON 字符串的<strong>浅层一致性</strong>,不适用于包含函数或 undefined 的复杂对象。</p>
</blockquote>
<hr>
<h3 id="更进一步由大佬们来把姿势实现下吧">更进一步由大佬们来把姿势实现下吧:</h3>
<ul>
<li>实现可配置的 <code>unique(arr, { deep: true, key: 'id' })</code> 工具函数</li>
<li>集成 lodash 或 Ramda 实现更强大的数据操作链</li>
</ul>
<p>欢迎评论区继续探讨!</p><br><br>
来源:https://www.cnblogs.com/zxlh1529/p/18983478
頁:
[1]