javaScript的序列化与反序列化

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对的序列化过程是对象的解析,以字符串形式存储对象结构。反序列化是解析字符串,还原成对象。理解这个过程,有助于我们解决复杂问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

18.3K Star,简洁强大下载利器

Hi&#xff0c;骚年&#xff0c;我是大 G&#xff0c;公众号「GitHub指北」会推荐 GitHub 上有趣有用的项目&#xff0c;一分钟 get 一个优秀的开源项目&#xff0c;挖掘开源的价值&#xff0c;欢迎关注。 今天推荐一个强大简洁下载利器&#xff0c;用于从各种网站下载图像/视…

Linux(一)

介绍 常见的操作系统(windows、IOS、Android、MacOS, Linux, Unix)&#xff1b; 一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发已经得到业界的认可&#xff1b;目前很多企业级的项目(c/c/php/python/java/go)都会部署到 Linux/unix 系统上。 吉祥物 …

leetcode刷题(剑指offer) 297.二叉树的序列化和反序列化

297.二叉树的序列化与反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作&#xff0c;进而可以将转换后的数据存储在一个文件或者内存中&#xff0c;同时也可以通过网络传输到另一个计算机环境&#xff0c;采取相反方式重构得到原数据。 请设计一个算法来实现…

使用wda框架实现IOS自动化测试详解

目录 1、weditor元素定位工具 1.1、weditor的安装和使用 2、wda iOS自动化框架 2.1、wda概述 2.2、wda安装 2.3、wda的使用 2.3.1、全局配置 2.3.2、创建客户端 2.3.3、APP相关操作 1、启动APP 2、关闭APP 3、获取APP状态信息 4、获取当前APP的运行信息 2.3.4、设…

ruoyi(若依)(el-menu也可参考)菜单栏过长显示省略号才显示气泡

一、背景 若依前后端分离的版本&#xff0c;新版本中优化了菜单名称过长悬停显示标题&#xff0c;但是是悬浮所有长度大于5的标题。可以查看提交记录&#xff1a;https://gitee.com/y_project/RuoYi-Cloud/commit/99932d91c0144da9f34f5bb05683cc0b86303217 但是我希望是只悬浮…

Vulnhub靶机:hacksudo2 (HackDudo)

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;hacksudo2 (HackDudo)&#xff08;10.0.2.44&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnh…

双非本科准备秋招(15.3)—— 力扣二叉树

今天学了二叉树结点表示法&#xff0c;建树代码如下。 public class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode(int val) {this.val val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left …

C++ | 部分和函数partial_sum的使用技巧

如果你需要处理一个数组的前缀和&#xff0c;或者数组中某一段元素的前缀和&#xff0c;你会怎么做呢&#xff1f; partial_sum函数是STL中的函数&#xff0c;用于计算范围的部分和&#xff0c;并从结果开始分配范围中的每个元素&#xff0c;range[first,last)中相应元素的部分…

MH-ET LIVE Boards(ATTiny88)实验一---点亮板载灯

MH-ET LIVE Boards(ATTiny88&#xff09;实验一点亮板载灯 在Arduino IDE中添加开发板资源包加入开发板json添加开发板 安装开发板驱动方法一&#xff1a;github下载2.0a4.rar方法二&#xff1a;开发板的package包中自带的2.0a4.rar安装驱动确认安装成功 blink.ino程序测试![在…

知识图谱嵌入学习在推理方法中的应用与挑战

目录 前言1 关系推理的嵌入模型1.1 嵌入模型介绍1.2 模型的差异1.3 嵌入模型的发展趋势 2 符号推理与向量推理3 嵌入模型的多样性4 强化学习与挑战5 元关系学习结论 前言 在人工智能领域&#xff0c;推理一直是关键任务之一。然而&#xff0c;传统的符号推理受限于人工定义&am…

【Vitis】Vitis HLS学习系列笔记 :第一个例程

在学习vitis的过程中一定要跑几个例程试试看&#xff0c;这中间遇到了几个小问题&#xff0c;记录下 有干货&#xff0c;请注意查收&#xff1a;作为新手&#xff0c;跑例程大概率会遇到问题&#xff0c;这里记录几个问题&#xff0c;如果刚好你也遇到&#xff0c;一定会帮到你…

每日一题——LeetCode1389.按既定顺序创建目标数组

方法一 splice 使用splice函数就可以在数组的指定索引位置添加元素 var createTargetArray function(nums, index) {let res[]for(let i0;i<nums.length;i){res.splice(index[i],0,nums[i])}return res }; 消耗时间和内存情况&#xff1a; 方法二 模拟 如果res[index[…

计算机网络——链路层(1)

计算机网络——链路层&#xff08;1&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU)前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c; [跳转到网站](https://www.captainbed.…

[每日一题] 02.03 - 质因数分解

质因数分解 枚举到n的平方根&#xff08;得包括平方根&#xff09; 偶数去除 import math n int(input()) if n % 2 0:print(max(n // 2,2)) else:for i in range(3,int(math.sqrt(n)) 1,2):if n % i 0:print(max(n // i,i))

2023年度总结 | 关于意义,爱与回望——写给清醒又无知的20岁

Hi&#xff0c;大家好&#xff0c;我是半亩花海&#xff0c;一名再普通不过的大学生。2023年&#xff0c;20岁&#xff0c;充实而零乱的一年&#xff0c;清醒又无知的一年。年末&#xff0c;最近的一些事儿也让我逐渐地有感而发&#xff0c;心静&#xff0c;除杂&#xff0c;思…

redis布隆过滤器(Bloom)详细使用教程

文章目录 布隆过滤器1. 原理2. 结构和操作3. 特点和应用场景4. 缺点和注意事项 应用-redis插件布隆过滤器使用详细过程安装以及配置springboot项目使用redis布隆过滤器下面是布隆过滤器的一些基础命令 扩展 布隆过滤器 Bloom 过滤器是一种概率型数据结构&#xff0c;用于快速判…

在低代码平台上实现精益软件开发:提高效率与灵活性的关键实践

什么是精益软件开发&#xff1f; 精益软件开发是一种敏捷的软件开发框架。它基于最小化浪费和最大化价值的原则。该框架基于最小可行产品策略运行&#xff0c;该策略强调交付具有基本基本功能的产品&#xff0c;然后根据收到的反馈进行迭代以即兴发挥并提供卓越。 精益软件开发…

编译opencv4.6问题汇总,第三方软件包见我发的资源

win10系统 python3.8.2&#xff0c;cmake-3.15.5-win64-x64&#xff0c;opencv4.6 编译方式见&#xff1a;OpenCV的编译 - 知乎 本文主要总结问题。赠人玫瑰手留余香。 问题1 Problem with installing OpenCV using Visual Studio and CMake (error code: MSB3073) 解决方法…

魔改冰蝎 —— 绕过检测,自动生成免杀后门

为什么要魔改工具&#xff1f; 生成的代码很容易被监测 生成的后门很容易被杀软杀掉 了解冰蝎流量特征 开启http代理&#xff0c;数据经过BP抓包进行分析数据 冰蝎数据包分析&#xff1a; 1、三个请求头固定 AcceptAccept-LanguageUser-Agent&#xff08;内部有十个&a…

VSCODE使用ssh远程连接时启动服务器失败问题

错误情况 ping服务器的ip可通并且使用terminal可以ssh连接到远程服务器。但使用vscode的remote-ssh时&#xff0c;在「输出」栏出现了一直报 Waiting for server log… 的情况&#xff01; 解决方法一 重置服务器设置&#xff0c;包括以下手段&#xff1a; 1.清理服务器端的…