iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >强大的JSON.stringify如何使用
  • 555
分享到

强大的JSON.stringify如何使用

2024-04-02 19:04:59 555人浏览 泡泡鱼
摘要

目录前言三参数replacer九特性特性一: undefined、函数、Symbol值特性二: toJSON() 方法特性三: 布尔值、数字、字符串的包装对象特性四: NaN Inf

前言

jsON.stringify 作为日常开发中经常使用的方法,你真的能灵活运用它吗?

学习本文之前,小包想让大家带着几个问题,一起来深入学习 stringify

  • stringify 函数有几个参数,每个参数分别有啥用啊?
  • stringify 序列化准则有哪些啊?
    • 函数序列化中会如何处理?
    • null、undefined、NaN 等特殊的值又会如何处理?
    • es6 后增加的 Symbol 类型、BigInt 序列化过程中会有特别处理吗?
  • stringify 为什么不适合做深拷贝?
  • 你能想到那些 stringify 的妙用?

整个文章的脉络跟下面思维导图一致,大家可以先留一下印象。

三参数

在日常编程中,我们经常 JSON.stringify 方法将某个对象转换成 JSON 字符串形式。

const stu = {
    name: 'zcxiaobao',
    age: 18
}

// {"name":"zcxiaobao","age":18}
console.log(JSON.stringify(stu));

stringify 真的就这么简单吗?我们先来看一下 MDN 中对 stringify 的定义。

MDN 中指出: JSON.stringify() 方法将一个 javascript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。

看完定义,小包就一惊,stringfy 不止一个参数吗?当然了,stringify 有三个参数。

咱们来看一下 stringify 语法和参数介绍:

JSON.stringify(value[, replacer [, space]])
  • value: 将要序列后成 JSON 字符串的值。
  • replacer(可选)

    如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;

    如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中

    如果该参数为 null 或者未提供,则对象所有的属性都会被序列化。

  • space(可选): 指定缩进用的空白字符串,用于美化输出

    如果参数是个数字,它代表有多少的空格。上限为10。

    该值若小于1,则意味着没有空格

    如果该参数为字符串(当字符串长度超过10个字母,取其前10个字母),该字符串将被作为空格

    如果该参数没有提供(或者为 null),将没有空格

replacer

我们来尝试一下 replacer 的使用。

  • replacer 作为函数

replacer 作为函数,它有两个参数,键(key) 和 值(value),并且两个参数都会被序列化。

在开始时,replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象。理解这点很重要,replacer 函数并非是上来就把对象解析成键值对形式,而是先传入了待序列化对象。随后每个对象或数组上的属性会被依次传入。 如果函数返回值为undefined或者函数时,该属性值会被过滤掉,其余按照返回规则。

// repalcer 接受两个参数 key value
// key value 分别为对象的每个键值对
// 因此我们可以根据键或者值的类型进行简单筛选
function replacer(key, value) {
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}
// function 可自己测试
function replacerFunc(key, value) {
  if (typeof value === "string") {
    return () => {};
  }
  return value;
}
const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
const jsonString = JSON.stringify(foo, replacer);

JSON 序列化结果为 {"week":45,"month":7}

但如果序列化的是数组,若 replacer 函数返回 undefined 或者函数,当前值不会被忽略,而将会被 null 取代。

const list = [1, '22', 3]
const jsonString = JSON.stringify(list, replacer)

JSON 序列化的结果为 '[1,null,3]'

  • replacer 作为数组

作为数组比较好理解,过滤数组中出现的键值。

const foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
const jsonString = JSON.stringify(foo, ['week', 'month']);

JSON 序列化结果为 {"week":45,"month":7}, 只保留 weekmonth 属性值。

九特性

特性一: undefined、函数、Symbol值

  • 出现在非数组对象属性值中: undefined、任意函数、Symbol 值在序列化过程中将会被忽略
  • 出现在数组中: undefined、任意函数、Symbol值会被转化为 null
  • 单独转换时: 会返回 undefined
// 1. 对象属性值中存在这三种值会被忽略
const obj = {
  name: 'zc',
  age: 18,
  // 函数会被忽略
  sayHello() {
    console.log('hello world')
  },
  // undefined会被忽略
  wife: undefined,
  // Symbol值会被忽略
  id: Symbol(111),
  // [Symbol('zc')]: 'zc',
}
// 输出结果: {"name":"zc","age":18}
console.log(JSON.stringify(obj));

// 2. 数组中这三种值会被转化为 null
const list = [
  'zc', 
  18, 
  // 函数转化为 null
  function sayHello() {
    console.log('hello world')
  }, 
  // undefined 转换为 null
  undefined, 
  // Symbol 转换为 null
  Symbol(111)
]

// ["zc",18,null,null,null]
console.log(JSON.stringify(list))

// 3. 这三种值单独转化将会返回 undefined

console.log(JSON.stringify(undefined))  // undefined
console.log(JSON.stringify(Symbol(111))) // undefined
console.log(JSON.stringify(function sayHello() { 
  console.log('hello world')
})) // undefined

特性二: toJSON() 方法

转换值如果有 toJSON() 方法,toJSON() 方法返回什么值,序列化结果就返回什么值,其余值会被忽略。

const obj = {
  name: 'zc',
  toJSON(){
    return 'return toJSON'
  }
}
// return toJSON
console.log(JSON.stringify(obj));

特性三: 布尔值、数字、字符串的包装对象

布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值

JSON.stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]);
// [1,"zcxiaobao",true]

特性四: NaN Infinity null

特性四主要针对 JavaScript 里面的特殊值,例如 Number 类型里的 NaNInfinity 及 null 。此三种数值序列化过程中都会被当做 null

// [null,null,null,null,null]
JSON.stringify([null, NaN, -NaN, Infinity, -Infinity])

// 特性三讲过布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
// 隐式类型转换就会调用包装类,因此会先调用 Number => NaN
// 之后再转化为 null
// 1/0 => Infinity => null
JSON.stringify([Number('123a'), +'123a', 1/0])

特性五: Date对象

Date 对象上部署了 toJSON 方法(同 Date.toISOString())将其转换为字符串,因此 JSON.stringify() 将会序列化 Date 的值为时间格式字符串

// "2022-03-06T08:24:56.138Z"
JSON.stringify(new Date())

特性六: Symbol

特性一提到,Symbol 类型当作值来使用时,对象、数组、单独使用分别会被忽略、转换为 null 、转化为 undefined

同样的,所有以 Symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们

const obj = {
  name: 'zcxiaobao',
  age: 18,
  [Symbol('lyl')]: 'unique'
}
function replacer(key, value) {
  if (typeof key === 'symbol') {
    return value;
  }
}

// undefined
JSON.stringify(obj, replacer);

通过上面案例,我们可以看出,虽然我们通过 replacer 强行指定了返回 Symbol 类型值,但最终还是会被忽略掉。

特性七: BigInt

JSON.stringify 规定: 尝试去转换 BigInt 类型的值会抛出 TypeError

const bigNumber = BigInt(1)
// Uncaught TypeError: Do not know how to serialize a BigInt
console.log(JSON.stringify(bigNumber))

特性八: 循环引用

特性八指出: 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误

日常开发中深拷贝最简单暴力的方式就是使用 JSON.parse(JSON.stringify(obj)),但此方法下的深拷贝存在巨坑,关键问题就在于 stringify 无法处理循环引用问题。

const obj = {
  name: 'zcxiaobao',
  age: 18,
}

const loopObj = {
  obj
}
// 形成循环引用
obj.loopObj = loopObj;
JSON.stringify(obj)


特性九: 可枚举属性

对于对象(包括 Map/Set/WeakMap/WeakSet)的序列化,除了上文讲到的一些情况,stringify 也明确规定,仅会序列化可枚举的属性

// 不可枚举的属性默认会被忽略
// {"age":18}
JSON.stringify(
    Object.create(
        null,
        {
            name: { value: 'zcxiaobao', enumerable: false },
            age: { value: 18, enumerable: true }
        }
    )
);

六妙用

localStorage

localStorage 对象用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去删除。通常我们以对象形式进行存储。

  • 单纯调用 localStorage 对象方法
const obj = {
  name: 'zcxiaobao',
  age: 18
}
// 单纯调用 localStorage.setItem()

localStorage.setItem('zc', obj);

// 最终返回结果是 [object Object]
// 可见单纯调用localStorage是失败的
console.log(localStorage.getItem('zc'))
  • localStorage 配合 JSON.stringify 方法
localStorage.setItem('zc', JSON.stringify(obj));

// 最终返回结果是 {name: 'zcxiaobao', age: 18}
console.log(JSON.parse(localStorage.getItem('zc')))

属性过滤

来假设这样一个场景,后端返回了一个很长的对象,对象里面属性很多,而我们只需要其中几个属性,并且这几个属性我们要存储到 localStorage 中。

  • 方案一: 解构赋值+ stringify
// 我们只需要 a,e,f 属性
const obj = {
  a:1, b:2, c:3, d:4, e:5, f:6, g:7
}
// 解构赋值
const {a,e,f} = obj;
// 存储到localStorage
localStorage.setItem('zc', JSON.stringify({a,e,f}))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc'))
  • 使用 stringifyreplacer 参数
// 借助 replacer 作为数组形式进行过滤
localStorage.setItem('zc', JSON.stringify(obj, ['a','e','f']))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc'))

replacer 是数组时,可以简单的过滤出我们所需的属性,是一个不错的小技巧。

三思而后行之深拷贝

使用 JSON.parse(JSON.stringify) 是实现对象的深拷贝最简单暴力的方法之一。但也正如标题所言,使用该种方法的深拷贝要深思熟虑。

  • 循环引用问题,stringify 会报错
  • 函数、undefinedSymbol 会被忽略
  • NaNInfinity-Infinity 会被序列化成 null
  • ...

因此在使用 JSON.parse(JSON.stringify) 做深拷贝时,一定要深思熟虑。如果没有上述隐患,JSON.parse(JSON.stringify) 是一个可行的深拷贝方案。

对象的 map 函数

在使用数组进行编程时,我们会经常使用到 map 函数。有了 replacer 参数后,我们就可以借助此参数,实现对象的 map 函数。

const ObjectMap = (obj, fn) => {
  if (typeof fn !== "function") {
    throw new TypeError(`${fn} is not a function !`);
  }
  // 先调用 JSON.stringify(obj, replacer) 实现 map 功能
  // 然后调用 JSON.parse 重新转化成对象
  return JSON.parse(JSON.stringify(obj, fn));
};

// 例如下面给 obj 对象的属性值乘以2

const obj = {
  a: 1,
  b: 2,
  c: 3
}
console.log(ObjectMap(obj, (key, val) => {
  if (typeof value === "number") {
    return value * 2;
  }
  return value;
}))

很多同学有可能会很奇怪,为什么里面还需要多加一部判断,直接 return value * 2 不可吗?

上文讲过,replacer 函数首先传入的是待序列化对象,对象 * 2 => NaN => toJSON(NaN) => undefined => 被忽略,就没有后续的键值对解析了。

删除对象属性

借助 replacer 函数,我们还可以删除对象的某些属性。

const obj = {
  name: 'zcxiaobao',
  age: 18
}
// {"age":18}
JSON.stringify(obj, (key, val) => {
  // 返回值为 undefined时,该属性会被忽略 
  if (key === 'name') {
    return undefined;
  }
  return val;
})

对象判断

JSON.stringify 可以将对象序列化为字符串,因此我们可以借助字符串的方法来实现简单的对象相等判断。

//判断数组是否包含某对象
const names = [
  {name:'zcxiaobao'},
  {name:'txtx'},
  {name:'mymy'},
];
const zcxiaobao = {name:'zcxiaobao'};
// true
JSON.stringify(names).includes(JSON.stringify(zcxiaobao))
 
// 判断对象是否相等
const d1 = {type: 'div'}
const d2 = {type: 'div'}

// true
JSON.stringify(d1) === JSON.stringify(d2);

数组对象去重

借助上面的思想,我们还能实现简单的数组对象去重。

但由于 JSON.stringify 序列化 {x:1, y:1}{y:1, x:1} 结果不同,因此在开始之前我们需要处理一下数组中的对象。

  • 方法一: 将数组中的每个对象的键按字典序排列
arr.forEach(item => {
  const newItem = {};
  Object.keys(item)   // 获取对象键值
        .sort()       // 键值排序
        .map(key => { // 生成新对象
          newItem[key] = item[key];
        })
  // 使用 newItem 进行去重操作
})

但方法一有些繁琐,JSON.stringify 提供了 replacer 数组格式参数,可以过滤数组。

  • 方法二: 借助 replacer 数组格式
function unique(arr) {
  const keySet = new Set();
  const uniqueObj = {}
  // 提取所有的键
  arr.forEach(item => {
    Object.keys(item).forEach(key => keySet.add(key))
  })
  const replacer = [...keySet];
  arr.forEach(item => {
    // 所有的对象按照规定键值 replacer 过滤
    unique[JSON.stringify(item, replacer)] = item;
  })
  return Object.keys(unique).map(u => JSON.parse(u))
}

// 测试一下
unique([{}, {}, 
      {x:1},
      {x:1},
      {a:1},
      {x:1,a:1},
      {x:1,a:1},
      {x:1,a:1,b:1}
      ])

// 返回结果
[{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1,"b":1}]

参考链接

  • 你不知道的 JSON.stringify() 的威力
  • JSON.parse(JSON.stringify(obj))实现深拷贝的弊端

到此这篇关于强大的JSON.stringify如何使用的文章就介绍到这了,更多相关JSON.stringify 使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 强大的JSON.stringify如何使用

本文链接: https://www.lsjlt.com/news/151447.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 强大的JSON.stringify如何使用
    目录前言三参数replacer九特性特性一: undefined、函数、Symbol值特性二: toJSON() 方法特性三: 布尔值、数字、字符串的包装对象特性四: NaN Inf...
    99+
    2024-04-02
  • javascript中JSON.stringify如何使用
    小编给大家分享一下javascript中JSON.stringify如何使用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!三参数在日常编程中,我们经常 JSON.stringify 方法将...
    99+
    2024-04-02
  • JavaScript如何使用JSON.stringify判空
    这篇文章将为大家详细讲解有关JavaScript如何使用JSON.stringify判空,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。JSON.stringify判空这种...
    99+
    2024-04-02
  • JSON.stringify如何运用
    本篇内容主要讲解“JSON.stringify如何运用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JSON.stringify如何运用”吧!语法JSON.stringify(value[,&n...
    99+
    2023-06-29
  • JavaScript的json.stringify()怎么使用
    使用JSON.stringify()方法可以将JavaScript对象转换为JSON字符串。语法:JSON.stringify(va...
    99+
    2023-08-09
    JavaScript
  • JavaScript JSON.stringify()的使用总结
    目录一、使用方法 1、基本用法 2、第二个参数--过滤器 3、第三个参数--字符串缩进 4、toJSON()方法--自定义JSON序列化 二、使用场景 1、判断数组是否包含某对象,或...
    99+
    2024-04-02
  • Linux下如何使用tmux打造更强大的终端
    这篇文章将为大家详细讲解有关Linux下如何使用tmux打造更强大的终端,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。安装并启动 tmuxtmux 应用程序的名称来源于终端(terminal)复用器(mu...
    99+
    2023-06-16
  • 学习Python中的Numpy:如何使用这个强大的容器?
    Python是一种非常流行的编程语言,因为它易于学习、易于阅读和编写,同时也具有很强的可扩展性。然而,Python的默认数据结构并不适合数值计算。在这种情况下,Numpy就是一个非常有用的工具。Numpy是一个Python库,用于处理大量...
    99+
    2023-09-08
    容器 numpy 日志
  • Unix Shell的强大功能:如何优雅地使用Laravel和Python?
    Unix Shell作为一种高效的命令行工具,在开发过程中发挥着重要的作用。利用Unix Shell,我们可以快速地进行文件操作、系统管理以及一些其他操作。而对于Web开发来说,Unix Shell更是必不可少的工具之一。在本文中,我们将...
    99+
    2023-11-01
    shell laravel unix
  • centos7使用vim打造强大的pyt
    编译升级vim centos7.3自带的vim是7.4.*版本, YouCompleteMe需要Vim 7.4.1578+我这里编译安装vim8.0 # 移除旧版本 sudo yum remove vim -y # 安装必要组件 sudo...
    99+
    2023-01-31
    强大 vim pyt
  • 如何在 Java 中使用 Windows API,让你的程序更加强大?
    Java 是一种强大的编程语言,但是有时候你可能需要使用 Windows API 扩展 Java 的功能,以便在 Windows 操作系统上运行更加高效的程序。在本文中,我们将探讨如何在 Java 中使用 Windows API,让你的程序...
    99+
    2023-08-27
    windows leetcode 打包
  • Flutter最强大的图表库fl_chart的使用
    文章目录 简介简单使用折线图柱状图饼图 简介 fl_chart是Flutter中功能最全、最强大的图表库。在flutter中的地位相当于前端的echarts、android端的MPAn...
    99+
    2023-09-14
    fl_chart Flutter
  • JSON.stringify如何使用数组过滤并序列化对象
    这篇文章主要介绍JSON.stringify如何使用数组过滤并序列化对象,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!使用数组过滤并序列化对象:// 使用“数组”当替代器 ...
    99+
    2024-04-02
  • 如何在 Windows 上使用 Bash 和 PHP 构建强大的应用程序?
    在过去,Windows操作系统是被开发者们遗忘的平台之一,因为Linux平台相对更适合开发者们的需求。然而,随着Microsoft推出了Windows Subsystem for Linux(WSL),Windows系统现在已经成为开发者们...
    99+
    2023-10-08
    bash load windows
  • 如何使用Go和Bash构建一个强大的数组框架?
    在计算机编程中,数组是一种非常常见的数据结构,它可以用来存储一系列的数据。使用数组可以很方便地对数据进行排序、搜索、过滤等操作。在本文中,我们将介绍如何使用Go和Bash构建一个强大的数组框架,帮助您更好地处理数据。 一、Go语言简介 G...
    99+
    2023-11-05
    bash 数组 框架
  • 详解如何解决使用JSON.stringify时遇到的循环引用问题
    程序员在日常做TypeScript/JavaScript开发时,经常需要将复杂的JavaScript对象通过JSON.stringify序列化成json字符串,保存到本地以便后续具体...
    99+
    2024-04-02
  • JS JSON.stringify()的5个使用场景详解
    目录前言第二个参数replacer 为数组第二个参数replacer 为函数第三个参数为 Number第三个参数为 StringtoJSON 方法总结前言 JSON.stringif...
    99+
    2023-01-28
    json.stringify()使用 jsonstringify作用 json.stringify
  • 如何在 Windows 上使用 Laravel 构建强大的 PHP 对象应用程序?
    Laravel 是一个流行的 PHP 开源框架,它提供了一种优雅的方式来构建 Web 应用程序。在本文中,我们将介绍如何在 Windows 上使用 Laravel 构建强大的 PHP 对象应用程序,并提供一些演示代码来帮助您入门。 安装...
    99+
    2023-07-24
    对象 laravel windows
  • 如何使用rlwrap增强sqlplus
    这篇文章主要介绍如何使用rlwrap增强sqlplus,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!添加epel源https://fedoraproject.org/wiki/EPE...
    99+
    2024-04-02
  • 如何使用React Portals实现一个功能强大的抽屉组件
    本篇内容介绍了“如何使用React Portals实现一个功能强大的抽屉组件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作