export const deteleObject = (arr) => {
let uniques = [];
let stringify = {};
for (let i = 0; i < arr.length; i++) {
let keys = Object.keys(arr[i]);
keys.sort((a, b) => {
return Number(a) - Number(b);
});
let str = '';
for (let j = 0; j < keys.length; j++) {
str += JSON.stringify(keys[j]);
str += JSON.stringify(arr[i][keys[j]]);
}
if (!Object.prototype.hasOwnProperty.call(stringify, str)) {
uniques.push(arr[i]);
stringify[str] = true;
}
}
return uniques;
};
这段代码是一个 JavaScript 函数,名为 deteleObject
(可能是 deleteObject
的拼写错误,意图是删除对象数组中的重复项)。函数接收一个数组 arr
作为参数,并返回一个去除重复对象的新数组 uniques
。
代码逐行解释:
-
export const deteleObject = (arr) => { ... };
:这是一个 ES6 箭头函数的导出语句,函数名为deteleObject
,接收一个参数arr
。 -
let uniques = [];
:声明一个空数组uniques
,用来存储不重复的对象。 -
let stringify = {};
:声明一个空对象stringify
,用来存储对象序列化后的唯一标识。 -
for (let i = 0; i < arr.length; i++) { ... }
:遍历输入数组arr
。 -
let keys = Object.keys(arr[i]);
:获取当前对象的所有键。 -
keys.sort((a, b) => { return Number(a) - Number(b); });
:对键数组进行排序,确保键的顺序是按照数值顺序排列。 -
let str = '';
:声明一个空字符串str
,用来构建当前对象的序列化字符串。 -
for (let j = 0; j < keys.length; j++) { ... }
:遍历排序后的键数组。 -
str += JSON.stringify(keys[j]);
:将键转换为字符串并连接到str
。 -
str += JSON.stringify(arr[i][keys[j]]);
:将当前键对应的值转换为字符串并连接到str
。 -
if (!Object.prototype.hasOwnProperty.call(stringify, str)) { ... }
:检查stringify
对象是否已经包含了由当前对象键值构建的序列化字符串。 -
uniques.push(arr[i]);
:如果stringify
中没有当前对象的序列化字符串,将当前对象添加到uniques
数组。 -
stringify[str] = true;
:在stringify
对象中记录当前对象的序列化字符串,以确保后续不会添加重复的对象。 -
return uniques;
:返回去重后的对象数组。
代码逻辑:
- 该函数通过比较对象的序列化字符串来识别重复项。对象的每个键值对都被转换为字符串并连接起来,形成对象的唯一标识。
- 使用
JSON.stringify
来序列化键和值,确保不同数据类型的键值对也能被正确比较。 - 使用
Object.prototype.hasOwnProperty.call
是为了检查stringify
对象是否拥有某个属性,避免直接使用stringify[str]
可能引起的问题。
注意事项:
- 该函数假设对象的键和值的序列化结果是对象的唯一标识。如果对象的顺序或格式对比较结果有影响,可能需要调整逻辑。
- 函数使用
JSON.stringify
来序列化键和值,这可能不会处理循环引用或特殊数据类型(如undefined
、function
等)。 - 函数的性能可能受到输入数组大小和对象复杂性的影响,因为它需要对每个对象进行序列化和比较。
这段代码在处理大型数组时可能会遇到性能问题,原因如下:
-
双层循环:代码中存在双层循环,外层循环遍历数组,内层循环遍历对象的键。对于大型数组和复杂对象,这可能导致较长的处理时间。
-
对象序列化:使用
JSON.stringify
对对象键值进行序列化是计算密集型的,尤其是当对象包含大量数据或复杂数据结构时。 -
字符串连接:在构建序列化字符串时,使用字符串连接(
+=
)可能不够高效,尤其是在循环中重复执行时。 -
对象属性检查:使用
Object.prototype.hasOwnProperty.call
来检查对象属性存在性是一个安全的做法,但可能影响性能。
优化方法:
-
减少序列化:如果对象的键是连续的数字且顺序一致,可以考虑使用数组的索引来代替序列化,从而避免重复序列化相同结构的对象。
-
使用 Map:使用
Map
对象代替普通对象来存储序列化字符串和对象的映射,因为Map
在处理大量数据时通常比普通对象更高效。 -
优化字符串操作:避免在循环中重复连接字符串。可以使用数组的
join
方法来一次性完成字符串的拼接。 -
并行处理:对于非常大的数组,可以考虑使用 Web Workers 来在后台线程处理数据,避免阻塞主线程。
-
使用散列:如果对象结构允许,可以使用更简洁的散列(hash)函数来代替序列化,减少字符串操作。
-
延迟执行:如果可能,延迟执行去重操作直到真正需要结果的时候。
-
分批处理:如果数组非常大,可以将其分成小批次进行处理,逐批处理和返回结果。
-
避免使用
JSON.stringify
:如果对象结构简单且类型不复杂,可以考虑自定义序列化函数,避免使用JSON.stringify
。 -
内存管理:在处理大量数据时,注意内存使用情况,适时释放不再使用的对象引用。
示例优化代码:
export const deleteObject = (arr) => {
const uniques = new Map();
const stringify = new Map();
for (const item of arr) {
const keys = Object.keys(item).sort((a, b) => Number(a) - Number(b));
let str = '';
for (const key of keys) {
str += key + ':' + JSON.stringify(item[key]);
}
if (!uniques.has(str)) {
uniques.set(str, item);
}
}
return Array.from(uniques.values());
};
在这个示例中,使用了 Map
来存储序列化字符串和对象的映射,同时使用 Array.from
来从 Map
中提取唯一的对象数组。这种方法可能在某些情况下提高性能,特别是在处理大型数据集时。