javaScript的序列化与反序列化

news2025/4/5 13:10:57

render函数的基本实现

javaScript的序列化与反序列化

    • 一,js中的序列化
    • 二,序列化
    • 三,反序列化
    • 四,总结

一,js中的序列化

js中序列化就是对象转换成json格式的字符串,使用JSON对象的stringify方法,接收一个javaScript对象,返回一个json字符串。主要使用场景用于数据传输和对象全等对比。

const person = {
  name: "John",
  age: 30,
  test: {
    tips: '我叫王大锤',
    site: 'http://www.example.com',
    screen: null
  },
  city: "New York",
};

JSON.stringify(person)

反序列化使用JSON对象的parse方法,接收一个json字符串。返回javaScript对象。主要使用场景,处理接口返回的数据,缓存数据处理。

JSON.parse(JSON.stringify(person))

本文主要讲述该功能的实现及序列化原理和反序列化

二,序列化

观察json数据的格式, 发现结构和javaScript的对象结构一样,只是整体都是字符串。原本的对象键都是用双引号包裹,值如果是字符串类型是也是双引号包裹,如果不是则是没有引号包裹。
在这里插入图片描述
数字和null值都没有被引号包裹。所以只有值是字符串的时候才需要被双引号包裹,其他类型直接转字符串。通过json字符串的规律,可以把对象对象变成json字符串。

class CustomJson {

  /**
   * 序列化函数
   * @param {object} param 
   * @returns {string}
   */
  stringify(param) {

    // 判断是否对象如果不是或不可转换成序列化字符串,抛出错误
    if (typeof param === 'object' && param !== null) {
    
      // 序列化回调函数
      const stringify = (p) => {

        const result = []
        
        // 分三种类型, 对象数组, 和非数组和对象或null类型
        // 使用栈的特性保存处理后的字符串, 也可以使用字符串拼接
        // 要手动拼接逗号
        // 字符串数据用双引号包裹再转成字符串, 其他基本类型数据直接转字符串
        if (Array.isArray(p)) {

          result.push('[')
          p.forEach((item, index) => {
            result.push(`${stringify(item)}${index !== p.length - 1 ? ',' : ''}`)
          })
          result.push(']')
        } else if (typeof p === 'object' && p !== null) {
          result.push('{')
          const len = Object.keys(p).length
          Object.keys(p).forEach((key, index) => {
            result.push(`"${key}":${stringify(p[key])}${(len - 1 !== index) ? ',' : ''}`)
          })
          result.push('}')
        } else {
          if (typeof p === 'string') {
            result.push(`"${p}"`)
          } else {
            result.push(`${p}`)
          }
        }
        // 最后将数组转换成字符串
        return result.join('')
      }
      return stringify(param)
    } else {
      throw new Error('param is not object')
    }
}

序列化验证一下

const person = {
  name: "John",
  age: 30,
  test: {
    tips: '我叫王大锤',
    site: 'http://www.example.com',
    screen: null,
    test: {
      tips: '我叫王大锤',
      site: 'http://www.example.com',
      screen: null,
      test: {
        tips: '我叫王大锤',
        site: 'http://www.example.com',
        screen: null,
      }
    }
  },
  city: "New York",
  list: [
    '1',
    2,
    3,
    {
      a: [
        {
          b: [1,2,3,4,5]
        }
      ]
    }
  ]
};
const test2 = [
  '1',
  2,
  3,
  {
    a: [
      {
        b: [1,2,3,4,5]
      }
    ]
  }
]
const explamJSon = new CustomJson()
const testStr = explamJSon.stringify(person)
console.log('testStr 序列化测试对象', testStr)
console.log('JSON.parse 使用原生反序列化', JSON.parse(testStr))

const testStr2 = explamJSon.stringify(test2)
console.log('testStr2 序列化测试对象', testStr2)
console.log('JSON.parse 使用原生反序列化', JSON.parse(testStr2))

可以正常转换成json字符串
在这里插入图片描述
为了验证格式的正确性,使用原生的JSON.parse反序列化转换成对象

const explamJSon = new CustomJson()
const testStr = explamJSon.stringify(person)

console.log(testStr)

console.log(JSON.parse(testStr))

在这里插入图片描述

测试结果,使用自定义序列化函数序列化的结果可以被原生的JSON.parse函数反序列化。验证成功。

三,反序列化

顾名思义反序列化与序列化的作用相反,序列化的时候我们将js对象转换成了json字符串。现在将json字符串转换成js对象。这个方法比序列化要复杂一些,序列化的时候对象本身格式是固定的。有特定的方法来处理。反序列化本身是要处理字符串,通过两分半的观察,json格式的字符串也是有规律的。每个属性之间的逗号可以作为分割符号来拆解字符串。拆解到最小颗粒度将值还原,最后返回结果。

class CustomJson {
  /**
   * 反序列化
   * @param {string} jsonData 
   * @returns {object}
   */
  parse (jsonData) {

    /**
     * 查询索引, 因为json之中使用英文逗号作为分割每一项, 使用栈先出,后进后出的特性, 获取,的坐标. 用数组存储返回
     * @param {string} str 
     * @returns {array}
     */
    const queryIdx = (str) => {
      const list = []
      let tempArr = []
      for (let i = 0; i < str.length; i += 1) {
        if (str[i] === '{' || str[i] === '[') {
          tempArr.push(str[i])
        }
        if (tempArr[tempArr.length - 1] === '{' && str[i] === '}') {
          tempArr.pop()
        }
        if (tempArr[tempArr.length - 1] === '[' && str[i] === ']') {
          tempArr.pop()
        }
        if (str[i] === ',' && tempArr.length === 0) {
          list.push(i)
        }
      }
      return list
    }
    /**
     * 还原数组, 在拿到分割坐标的基础之上, 将json字负串分解成字符串片段, 用数组存储返回
     * @param {string} val 
     * @returns {array}
     */
    const splitObject = (val) => {
      const s = val.slice(1, val.length - 1)
      const idxList = queryIdx(s)
      const tempArr = []
      let silceIdx = 0
      idxList.forEach(idx => {
        tempArr.push(s.slice(silceIdx, idx))
        silceIdx = idx + 1
      })
      tempArr.push(s.slice(silceIdx))
      return tempArr
    }
    /**
     * 分解字符串, 分别处理数组和对象
     * @param {string} str 
     * @returns {object}
     */
    const decomposeStr = (str) => {
      /**
       * 判断是不是一个合法的json字符串, 如果不是抛出错误
       */
      if (jsonData[0] === '{' && jsonData[jsonData.length - 1] !== '}' || jsonData[0] === '[' && jsonData[jsonData.length - 1] !== ']') {
        throw new Error('jsonData is not json string')
      } else if (jsonData[0] != '{' || jsonData[0] === '[') {
        throw new Error('jsonData is not json string')
      }
      const result = str[0] === '[' ? [] : {}
      if (Array.isArray(result)) {
        const arr = splitObject(str)
        arr.forEach(item => {
          if (item.trim()[0] === '{' && item.trim()[item.trim().length - 1] === '}' || item.trim()[0] === '[' && item.trim()[item.trim().length - 1] === ']'){
            result.push(decomposeStr(item.trim()))
          } else {
            result.push(convertVlaue(item.trim()))
          }
        })
      } else {
        const arr = splitObject(str)
        arr.forEach(item => {
          if (item.trim()[0] === '{' && item.trim()[item.trim().length - 1] === '}' || item.trim()[0] === '[' && item.trim()[item.trim().length - 1] === ']'){
            result.push(decomposeStr(item.trim()))
          } else {
            const keyValues = item.trim()
            const divideIdx = keyValues.indexOf(':')
            const key = keyValues.slice(0, divideIdx)
            const value = keyValues.slice(divideIdx + 1)
            result[key.trim().slice(1, key.length - 1)] = convertVlaue(value)
          }
        })
      }
      return result
    }
    /**
     * 转换值, 根据之前不同的类型,将值还原, 
     * 在序列化的时候, 因为特殊处理了字符串数据,发现是有双引号包裹的去掉双引号.
     * 没有双引号包裹的特殊值,特殊处理
     * @param {string} val 
     * @returns {any}
     */
    const convertVlaue = (val) => {
      if (val[0] === '"' && val[val.length - 1] === '"') {
        return val.slice(1, val.length - 1)
      } else if (val === 'null') {
        return null
      } else if (val === 'true') {
        return true
      } else if (val === 'false') {
        return false
      } else if (val === 'NaN') {
        return NaN
      } else if (Number(val) === 0 || Number(val)) {
        return Number(val)
      } else if (val[0] === '{' && val[val.length - 1] === '}' || val[0] === '[' && val[val.length - 1] === ']') {
        return decomposeStr(val)
      } else {
        return val.trim()
      }
    }
    return decomposeStr(jsonData)
  }
}

测试


console.log('使用自定义反序列化', explamJSon.parse(testStr))
console.log('原生JSON.stringify序列化自定义反序列化结果', JSON.parse(testStr))

能够在原生与自定义之间转换。
在这里插入图片描述
异常判断

const explamJSon = new CustomJson()
// 非合法json字符串
console.log('异常判断', explamJSon.parse('1111'))
// 非合法对象
console.log('异常判断', explamJSon.stringify('1111'))

在这里插入图片描述

四,总结

总的来说,javaScript对的序列化过程是对象的解析,以字符串形式存储对象结构。反序列化是解析字符串,还原成对象。理解这个过程,有助于我们解决复杂问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1426429.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R-YOLO

Abstract 提出了一个框架&#xff0c;名为R-YOLO&#xff0c;不需要在恶劣天气下进行注释。考虑到正常天气图像和不利天气图像之间的分布差距&#xff0c;我们的框架由图像翻译网络&#xff08;QTNet&#xff09;和特征校准网络&#xff08;FCNet&#xff09;组成&#xff0c;…

vue3-深入组件-依赖注入

Prop 逐级透传问题 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。 如果是多层级嵌套的组件&#xff0c;如何从一级传递到 3 级甚至更远呢。 若使用 props 则必须将其沿着组件链逐级传递下去&#xff0c;这会非常麻烦&#xff0c;所…

canvas路径剪裁clip(图文示例)

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

jupyter notebook显示的扩展很少,只有四五个--解决方案

如下&#xff1a;安装好只有四五个扩展 可以先删除 conda remove jupyter_nbextensions_configurator 然后使用pip安装 pip install jupyter_contrib_nbextensions jupyter contrib nbextensions install --user pip install jupyter_nbextensions_configurator jupyter nbex…

MySQL-运维-主从复制

一、概述 二、原理 三、搭建 1、服务器准备 2、主库配置 &#xff08;1&#xff09;、修改配置文件/etc/my.cnf &#xff08;2&#xff09;、重启MySQL服务器 &#xff08;3&#xff09;、登录mysql&#xff0c;创建远程链接的账号&#xff0c;并授予主从复制权限 &#xff0…

Kafka-服务端-GroupCoordinator

在每一个Broker上都会实例化一个GroupCoordinator对象&#xff0c;Kafka按照Consumer Group的名称将其分配给对应的GroupCoordinator进行管理&#xff1b; 每个GroupCoordinator只负责管理Consumer Group的一个子集&#xff0c;而非集群中全部的Consumer Group。 请注意与Kaf…

华媒舍:10个与汽车媒体国外传播有关的方向

随着近年来汽车销售市场的不断增加与发展&#xff0c;汽车媒体国外传播已经成为汽车行业里至关重要的一环。下面我们就详细介绍10个与汽车媒体国外传播有关的发展方向&#xff0c;并讨论这些趋势对全世界汽车行业的影响。 1.智能化媒体的兴起伴随着互联网的发展与发展&#xff…

2024年第4届IEEE软件工程与人工智能国际会议(SEAI 2024)

2024年第4届IEEE软件工程与人工智能国际会议(SEAI 2024)将于2024年6月21-23日在中国厦门举办。 SEAI旨在为软件工程与人工智能领域搭建高端前沿的交流平台&#xff0c;推动产业发展。本次会议将汇聚海内外的知名专家、学者和产业界优秀人才&#xff0c;共同围绕国际热点话题、核…

地理坐标系、空间坐标系、epsg查询网站

坐标系可用范围和详细信息的查询网站 简介 epsg.ruiduobao.com是一个可以查询gdal中所有坐标系信息的网站&#xff0c;可查询到坐标系的基准面、椭球体、中央子午线等相关信息&#xff0c;并对每个坐标系的可用范围在地图中进行了显示。详细信息可以看操作视频&#xff1a; e…

bank conflict

前置知识&#xff1a; shared memory 被分成 32 个 bank一个 warp 32 个线程每个 bank 4 byte如果同一 warp 中不同线程访问同一 bank 的不同地址则发生 bank conflict 请注意需要是一个 warp 中的不同线程&#xff01;如果一个线程访问 shared memory 的两个元素&#xff0c;…

【ArcGIS Pro】从0开始

1.导入excel&#xff0c;需要安装驱动程序 安装用于 Microsoft Excel 文件的驱动程序 https://pro.arcgis.com/zh-cn/pro-app/latest/help/data/excel/prepare-to-work-with-excel-in-arcgis-pro.htm 2.修改投影坐标系 点到地图图标上&#xff0c;右键才能设置坐标系。 3.…

MSVC++远程调试

1. 介绍 MSVC的调试功能非常强大&#xff0c;可以下断点&#xff0c;单步调试&#xff0c;查看堆栈变量信息等。实际用于生产的电脑环境复杂&#xff0c;更容易发生Bug。生产电脑&#xff0c;由于各种原因有些可能无法安装MSVC用来现场调试。基于打印日志&#xff0c;查看日志…

Elasticsearch:将文档级安全性 (DLS) 添加到你的内部知识搜索

作者&#xff1a;来自 Elastic Sean Story 你的企业很可能淹没在内部数据中。 你拥有问题跟踪、笔记记录、会议记录、维基页面、视频录制、聊天以及即时消息和私信。 并且不要忘记电子邮件&#xff01; 难怪如此多的企业都在尝试创造工作场所搜索体验 - 为员工提供集中、一站…

如何部署Docker Registry并实现无公网ip远程连接本地镜像仓库

文章目录 1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址 Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现远程pull or push (拉取和推送)…

java程序读取并控制串口设备

监听串口&#xff0c;接收它们发过来的数据&#xff0c;进行处理。 一、概况 前不久做的一个项目&#xff0c;需要读取水下传感器的数据。这些传感器通过串口与外界交互。我们写了一个java程序&#xff0c;接收传感器传送的数据&#xff0c;同时也下发命令&#xff0c;控制部…

车载电子电器架构 —— IP地址获取策略

车载电子电器架构 —— IP地址获取策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自…

DHCP简介

定义 动态主机配置协议DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;是一种用于集中对用户IP地址进行动态管理和配置的技术。即使规模较小的网络&#xff0c;通过DHCP也可以使后续增加网络设备变得简单快捷。 DHCP是在BOOTP&#xff08;BOOTstrap Protoc…

WiFi 7 的核心要点

目录 WiFi 7 是什么&#xff1f; WiFi 7 的主要feature功能&#xff1a; 320Mhz channel 4K QAM Multi-Link Operation (MLO)&#xff0c;多链路操作 512 block ACK OFDMA&#xff1a;multiple RUs to single STA. 总结&#xff1a;性能是第一优先级&#xff0c;WiFi 7&#xf…

Java的JVM学习一

一、java中的内存结构如何划分 栈和堆的区别&#xff1a; 栈负责处理运行&#xff0c;堆负债处理存储。 区域名称作用虚拟机栈用于存储正在执行的每个Java方法&#xff0c;以及其方法的局部变量表等。局部变量表存放了便器可知长度的各种基本数据类型&#xff0c;对象引用&am…

Vue3_基础使用

vue2的选项式与vue3的组合式区别&#xff1a; 选项式&#xff1a;vue2中数据与方法计算属性等等&#xff0c;针对一个数据的处理在不同的配置中&#xff0c;当业务复杂时很难维护&#xff0c;修改起来也不好查找。 vue3的组合式&#xff1a;将针对数据的方法计算属性等等放在一…