除了 JSON 序列化比较,还有哪些方法可以进行深比较?

简介: 【10月更文挑战第29天】

使用lodash或underscore.js库的深度比较函数

  • lodash的 _.isEqual 方法

    • 原理:lodash是一个广泛使用的JavaScript实用工具库,其 _.isEqual 方法通过递归遍历对象和数组的所有属性和元素,对不同的数据类型进行细致的比较,能够处理各种复杂的数据结构,包括循环引用等特殊情况。
    • 示例

      const _ = require('lodash');
      
      let obj1 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      let obj2 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      
      console.log(_.isEqual(obj1, obj2)); // true
      
      let obj3 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      let obj4 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      
      console.log(_.isEqual(obj3, obj4)); // true
      
  • underscore.js的 _.isEqual 方法

    • 原理:underscore.js同样提供了 _.isEqual 方法来进行深度比较,其实现原理与lodash类似,通过递归和类型判断等方式对对象和数组进行全面的比较,以确定它们是否在结构和值上完全相等。
    • 示例

      const _ = require('underscore');
      
      let obj1 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      let obj2 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      
      console.log(_.isEqual(obj1, obj2)); // true
      
      let obj3 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      let obj4 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      
      console.log(_.isEqual(obj3, obj4)); // true
      

基于对象属性遍历和类型判断的自定义比较函数

  • 原理:这种方法需要开发者手动编写比较逻辑,通过遍历对象的属性,针对不同的数据类型进行相应的比较操作。对于对象类型的属性,继续递归调用比较函数进行深度比较;对于数组类型的属性,遍历数组元素并逐个比较。
  • 示例
function customDeepEqual(obj1, obj2) {
   
  // 比较对象的类型是否相同
  if (Object.prototype.toString.call(obj1)!== Object.prototype.toString.call(obj2)) {
   
    return false;
  }

  if (typeof obj1 === 'object' && obj1!== null) {
   
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);

    if (keys1.length!== keys2.length) {
   
      return false;
    }

    for (let key of keys1) {
   
      if (!obj2.hasOwnProperty(key)) {
   
        return false;
      }

      if (typeof obj1[key] === 'object' && obj1[key]!== null) {
   
        if (!customDeepEqual(obj1[key], obj2[key])) {
   
          return false;
        }
      } else {
   
        if (obj1[key]!== obj2[key]) {
   
          return false;
        }
      }
    }
  }

  return true;
}

let obj1 = {
    name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
let obj2 = {
    name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };

console.log(customDeepEqual(obj1, obj2)); // true

let obj3 = {
    name: 'Alice', age: 25, details: {
    city: 'New York' } };
let obj4 = {
    name: 'Alice', age: 25, details: {
    city: 'New York' } };

console.log(customDeepEqual(obj3, obj4)); // true

使用Proxy对象进行代理比较

  • 原理:利用ES6的Proxy对象可以拦截对象的操作,通过定义 getset 等拦截器,在访问和修改对象属性时进行额外的处理。在深度比较中,可以使用Proxy来代理对象,在属性访问时记录属性值,并递归比较属性值是否相等。
  • 示例
function deepEqualWithProxy(obj1, obj2) {
   
  const seen = new WeakSet();

  const proxyHandler = {
   
    get(target, property) {
   
      if (typeof target[property] === 'object' && target[property]!== null) {
   
        if (!seen.has(target[property])) {
   
          seen.add(target[property]);
          return new Proxy(target[property], proxyHandler);
        }
      }
      return target[property];
    }
  };

  const proxiedObj1 = new Proxy(obj1, proxyHandler);
  const proxiedObj2 = new Proxy(obj2, proxyHandler);

  return JSON.stringify(proxiedObj1) === JSON.stringify(proxiedObj2);
}

let obj1 = {
    name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
let obj2 = {
    name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };

console.log(deepEqualWithProxy(obj1, obj2)); // true

let obj3 = {
    name: 'Alice', age: 25, details: {
    city: 'New York' } };
let obj4 = {
    name: 'Alice', age: 25, details: {
    city: 'New York' } };

console.log(deepEqualWithProxy(obj3, obj4)); // true

这种方法结合了Proxy对象的特性和JSON序列化比较的优点,能够处理循环引用等复杂情况,同时又相对简洁直观。

使用第三方深度比较库,如 deep-equal、fast-deep-equal等

  • deep-equal库

    • 原理:该库专门用于深度比较JavaScript对象和数组,它通过递归遍历对象和数组的属性和元素,对各种数据类型进行准确的比较,支持处理循环引用等复杂的数据结构。
    • 示例

      const deepEqual = require('deep-equal');
      
      let obj1 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      let obj2 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      
      console.log(deepEqual(obj1, obj2)); // true
      
      let obj3 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      let obj4 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      
      console.log(deepEqual(obj3, obj4)); // true
      
  • fast-deep-equal库

    • 原理:与其他深度比较库类似,fast-deep-equal通过优化的算法和数据结构,快速而准确地对对象和数组进行深度比较,能够在保证比较准确性的前提下,提高比较的效率。
    • 示例

      const fastDeepEqual = require('fast-deep-equal');
      
      let obj1 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      let obj2 = {
              name: 'Alice', age: 25, hobbies: ['reading', 'swimming'] };
      
      console.log(fastDeepEqual(obj1, obj2)); // true
      
      let obj3 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      let obj4 = {
              name: 'Alice', age: 25, details: {
              city: 'New York' } };
      
      console.log(fastDeepEqual(obj3, obj4)); // true
      

这些方法都可以用于进行深比较,各有优缺点。在实际应用中,可以根据具体的项目需求、性能要求、数据结构的复杂程度以及是否愿意引入第三方库等因素,选择合适的深比较方法。

相关文章
|
3月前
|
XML 存储 JSON
Twaver-HTML5基础学习(19)数据容器(2)_数据序列化_XML、Json
本文介绍了Twaver HTML5中的数据序列化,包括XML和JSON格式的序列化与反序列化方法。文章通过示例代码展示了如何将DataBox中的数据序列化为XML和JSON字符串,以及如何从这些字符串中反序列化数据,重建DataBox中的对象。此外,还提到了用户自定义属性的序列化注册方法。
51 1
|
3天前
|
JSON 人工智能 算法
探索大型语言模型LLM推理全阶段的JSON格式输出限制方法
本篇文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。
|
1月前
|
JSON JavaScript 前端开发
Go语言中json序列化的一个小坑,建议多留意一下
在Go语言开发中,JSON因其简洁和广泛的兼容性而常用于数据交换,但其在处理数字类型时存在精度问题。本文探讨了JSON序列化的一些局限性,并介绍了两种替代方案:Go特有的gob二进制协议,以及msgpack,两者都能有效解决类型保持和性能优化的问题。
54 7
|
1月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
50 4
|
1月前
|
JSON JavaScript Java
对比JSON和Hessian2的序列化格式
通过以上对比分析,希望能够帮助开发者在不同场景下选择最适合的序列化格式,提高系统的整体性能和可维护性。
48 3
|
1月前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
1月前
|
JSON 人工智能 算法
探索LLM推理全阶段的JSON格式输出限制方法
文章详细讨论了如何确保大型语言模型(LLMs)输出结构化的JSON格式,这对于提高数据处理的自动化程度和系统的互操作性至关重要。
197 12
|
3月前
|
XML JSON JavaScript
JSON对象的stringify()和parse()方法使用
本文阐述了JSON对象的`stringify()`和`parse()`方法的用法,包括如何将JavaScript对象转换为JSON字符串,以及如何将JSON字符串解析回JavaScript对象,并讨论了转换过程中需要注意的事项。
JSON对象的stringify()和parse()方法使用
|
3月前
|
JSON Go 数据格式
Golang语言结构体链式编程与JSON序列化
这篇文章是关于Go语言中结构体链式编程与JSON序列化的教程,详细介绍了JSON格式的基本概念、结构体的序列化与反序列化、结构体标签的使用以及如何实现链式编程。
47 4
|
3月前
|
JSON 数据格式
序列化 json和pickle
序列化 json和pickle