JavaScript数组中“重复数据引用”指多个元素指向同一对象内存地址,修改一处会影响其他项;需用===或Object.is()识别引用相同,避免JSON.stringify误判;初始化应每次新建对象,已有重复引用需浅拷贝(如{...item})或structuredClone()深拷贝;逻辑去重应基于唯一键而非引用。

JavaScript 数组中出现“重复数据引用”,通常不是值重复,而是多个数组项指向同一个对象(或函数、数组等引用类型)的内存地址。这种情况下,修改其中一个项会影响其他项,容易引发隐蔽 bug。关键在于区分「值相等」和「引用相同」,并根据需求选择深拷贝、浅拷贝或去重策略。
识别是否为同一引用
用 === 或 Object.is() 判断两个元素是否指向同一对象:
- 若
arr[0] === arr[1]返回true,说明它们是同一引用 - 普通值(字符串、数字、布尔)用
===比较没问题;对象/数组必须用引用比较才准确 - 避免误用
JSON.stringify(a) === JSON.stringify(b),它无法识别循环引用,且会忽略函数、undefined、Symbol 等
避免创建重复引用
初始化数组时,不要多次 push 同一个对象实例:
- ❌ 错误写法:
const obj = { x: 1 }; const arr = [obj, obj, obj]; - ✅ 正确写法(每次新建):
const arr = Array.from({ length: 3 }, () => ({ x: 1 })); - ✅ 或用 map 创建独立副本:
const base = { x: 1 }; const arr = [1,2,3].map(() => ({ ...base }));
分离已有重复引用(浅层解耦)
如果数组已存在多个相同引用,需为每个位置生成独立副本:
立即学习“Java免费学习笔记(深入)”;
- 对象:用展开运算符
{...item}或Object.assign({}, item)(仅一层) - 数组:用扩展符
[...item]或item.slice() - 注意:这些只是浅拷贝,嵌套对象仍共享引用;深层结构需结构化克隆或递归拷贝
- 现代环境可用
structuredClone()(支持多数类型,含嵌套对象、日期、Map/Set)
按值去重而非按引用去重
当目标是“逻辑去重”(如过滤掉内容相同的对象),不能直接用 Set 或 filter + indexOf,因为对象引用不同但内容可能一致:
- 先序列化再比较(适合简单可序列化结构):
arr.filter((item, i, a) => a.findIndex(v => JSON.stringify(v) === JSON.stringify(item)) === i) - 更健壮方式:自定义唯一键,例如用某个字段(
id):arr.filter((item, i, a) => a.findIndex(v => v.id === item.id) === i) - 复杂结构建议用 Lodash 的
uniqBy(arr, 'id')或isEqual配合uniqWith
处理引用重复的核心是明确意图:要的是独立副本,还是逻辑去重?前者靠拷贝,后者靠特征提取。不复杂但容易忽略细节。


















