JavaScript学习记录23

第十一节 JSON对象

1. JSON 格式

JSON 格式(JavaScript Object Notation 的缩写)是一种用于数据交换的文本格式,2001年由 Douglas Crockford 提出,目的是取代繁琐笨重的 XML 格式。

相比 XML 格式,JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON 迅速被接受,已经成为各大网站交换数据的标准格式,并被写入标准。

每个 JSON 对象就是一个值,可能是一个数组或对象,也可能是一个原始类型的值。总之,只能是一个值,不能是两个或更多的值。

JSON 对值的类型和格式有严格的规定。

复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinity和undefined)。字符串必须使用双引号表示,不能使用单引号。对象的键名必须放在双引号里面。数组或对象最后一个成员的后面,不能加逗号。

以下都是合法的 JSON。

["one", "two", "three"]{ "one": 1, "two": 2, "three": 3 }{"names": ["张三", "李四"] }[ { "name": "张三"}, {"name": "李四"} ]

以下都是不合法的 JSON。

{ name: "张三", 'age': 32 }  // 属性名必须使用双引号[32, 64, 128, 0xFFF] // 不能使用十六进制值{ "name": "张三", "age": undefined } // 不能使用 undefined{ "name": "张三","birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),"getName": function () {return this.name;}
} // 属性值不能使用函数和日期对象

注意,null、空数组和空对象都是合法的 JSON 值。

2. JSON 对象

JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。它有两个静态方法:JSON.stringify()和JSON.parse()。

3. JSON.stringify()

3.1 基本用法

JSON.stringify()方法用于将一个值转为 JSON 字符串。该字符串符合 JSON 格式,并且可以被JSON.parse()方法还原。

JSON.stringify('abc') // ""abc""
JSON.stringify(1) // "1"
JSON.stringify(false) // "false"
JSON.stringify([]) // "[]"
JSON.stringify({}) // "{}"JSON.stringify([1, "false", false])
// '[1,"false",false]'JSON.stringify({ name: "张三" })
// '{"name":"张三"}'

上面代码将各种类型的值,转成 JSON 字符串。

注意,对于原始类型的字符串,转换结果会带双引号。

JSON.stringify('foo') === "foo" // false
JSON.stringify('foo') === "\"foo\"" // true

上面代码中,字符串foo,被转成了"\"foo\""。这是因为将来还原的时候,内层双引号可以让 JavaScript 引擎知道,这是一个字符串,而不是其他类型的值。

JSON.stringify(false) // "false"
JSON.stringify('false') // "\"false\""

上面代码中,如果不是内层的双引号,将来还原的时候,引擎就无法知道原始值是布尔值还是字符串。

如果对象的属性是undefined、函数或 XML 对象,该属性会被JSON.stringify()过滤。

var obj = {a: undefined,b: function () {}
};JSON.stringify(obj) // "{}"

上面代码中,对象obj的a属性是undefined,而b属性是一个函数,结果都被JSON.stringify过滤。

如果数组的成员是undefined、函数或 XML 对象,则这些值被转成null。

var obj = {a: undefined,b: function () {}
};JSON.stringify(obj) // "{}"

上面代码中,数组arr的成员是undefined和函数,它们都被转成了null。

正则对象会被转成空对象。

JSON.stringify(/foo/) // "{}"

JSON.stringify()方法会忽略对象的不可遍历的属性。

var obj = {};
Object.defineProperties(obj, {'foo': {value: 1,enumerable: true},'bar': {value: 2,enumerable: false}
});JSON.stringify(obj); // "{"foo":1}"

上面代码中,bar是obj对象的不可遍历属性,JSON.stringify方法会忽略这个属性。

3.2 第二个参数

JSON.stringify()方法还可以接受一个数组,作为第二个参数,指定参数对象的哪些属性需要转成字符串。

var obj = {'prop1': 'value1','prop2': 'value2','prop3': 'value3'
};var selectedProperties = ['prop1', 'prop2'];JSON.stringify(obj, selectedProperties)
// "{"prop1":"value1","prop2":"value2"}"

上面代码中,JSON.stringify()方法的第二个参数指定,只转prop1和prop2两个属性。

这个类似白名单的数组,只对对象的属性有效,对数组无效。

JSON.stringify(['a', 'b'], ['0'])
// "["a","b"]"JSON.stringify({0: 'a', 1: 'b'}, ['0'])
// "{"0":"a"}"

上面代码中,第二个参数指定 JSON 格式只转0号属性,实际上对数组是无效的,只对对象有效。

第二个参数还可以是一个函数,用来更改JSON.stringify()的返回值。

function f(key, value) {if (typeof value === "number") {value = 2 * value;}return value;
}JSON.stringify({ a: 1, b: 2 }, f)
// '{"a": 2,"b": 4}'

上面代码中的f函数,接受两个参数,分别是被转换的对象的键名和键值。如果键值是数值,就将它乘以2,否则就原样返回。

注意,这个处理函数是递归处理所有的键。

var obj = {a: {b: 1}};function f(key, value) {console.log("["+ key +"]:" + value);return value;
}JSON.stringify(obj, f)
// []:[object Object]
// [a]:[object Object]
// [b]:1
// '{"a":{"b":1}}'

上面代码中,对象obj一共会被f函数处理三次,输出的最后那行是JSON.stringify()的默认输出。第一次键名为空,键值是整个对象obj;第二次键名为a,键值是{b: 1};第三次键名为b,键值为1。

递归处理中,每一次处理的对象,都是前一次返回的值。

var obj = {a: 1};function f(key, value) {if (typeof value === 'object') {return {b: 2};}return value * 2;
}JSON.stringify(obj, f)
// "{"b": 4}"

上面代码中,f函数修改了对象obj,接着JSON.stringify()方法就递归处理修改后的对象obj。

如果处理函数返回undefined或没有返回值,则该属性会被忽略。

function f(key, value) {if (typeof(value) === "string") {return undefined;}return value;
}JSON.stringify({ a: "abc", b: 123 }, f)
// '{"b": 123}'

上面代码中,a属性经过处理后,返回undefined,于是该属性被忽略了。

3.3 第三个参数

JSON.stringify()还可以接受第三个参数,用于增加返回的 JSON 字符串的可读性。

默认返回的是单行字符串,对于大型的 JSON 对象,可读性非常差。第三个参数使得每个属性单独占据一行,并且将每个属性前面添加指定的前缀(不超过10个字符)。

// 默认输出
JSON.stringify({ p1: 1, p2: 2 })
// JSON.stringify({ p1: 1, p2: 2 })// 分行输出
JSON.stringify({ p1: 1, p2: 2 }, null, '\t')
// {
// 	"p1": 1,
// 	"p2": 2
// }

上面例子中,第三个属性\t在每个属性前面添加一个制表符,然后分行显示。

第三个属性如果是一个数字,则表示每个属性前面添加的空格(最多不超过10个)。

JSON.stringify({ p1: 1, p2: 2 }, null, 2);
/*
"{"p1": 1,"p2": 2
}"
*/

3.4 参数对象的 toJSON() 方法

如果参数对象有自定义的toJSON()方法,那么JSON.stringify()会使用这个方法的返回值作为参数,而忽略原对象的其他属性。

下面是一个普通的对象。

var user = {firstName: '三',lastName: '张',get fullName(){return this.lastName + this.firstName;}
};JSON.stringify(user)
// "{"firstName":"三","lastName":"张","fullName":"张三"}"

现在,为这个对象加上toJSON()方法。

var user = {firstName: '三',lastName: '张',get fullName(){return this.lastName + this.firstName;},toJSON: function () {return {name: this.lastName + this.firstName};}
};JSON.stringify(user)
// "{"name":"张三"}"

上面代码中,JSON.stringify()发现参数对象有toJSON()方法,就直接使用这个方法的返回值作为参数,而忽略原对象的其他参数。

Date对象就有一个自己的toJSON()方法。

var date = new Date('2015-01-01');
date.toJSON() // "2015-01-01T00:00:00.000Z"
JSON.stringify(date) // ""2015-01-01T00:00:00.000Z""

上面代码中,JSON.stringify()发现处理的是Date对象实例,就会调用这个实例对象的toJSON()方法,将该方法的返回值作为参数。

toJSON()方法的一个应用是,将正则对象自动转为字符串。因为JSON.stringify()默认不能转换正则对象,但是设置了toJSON()方法以后,就可以转换正则对象了。

var obj = {reg: /foo/
};// 不设置 toJSON 方法时
JSON.stringify(obj) // "{"reg":{}}"// 设置 toJSON 方法时
RegExp.prototype.toJSON = RegExp.prototype.toString;
JSON.stringify(/foo/) // ""/foo/""

上面代码在正则对象的原型上面部署了toJSON()方法,将其指向toString()方法,因此转换成 JSON 格式时,正则对象就先调用toJSON()方法转为字符串,然后再被JSON.stringify()方法处理。

4. JSON.parse()

JSON.parse()方法用于将 JSON 字符串转换成对应的值。

JSON.parse('{}') // {}
JSON.parse('true') // true
JSON.parse('"foo"') // "foo"
JSON.parse('[1, 5, "false"]') // [1, 5, "false"]
JSON.parse('null') // nullvar o = JSON.parse('{"name": "张三"}');
o.name // 张三

如果传入的字符串不是有效的 JSON 格式,JSON.parse()方法将报错。

JSON.parse("'String'") // illegal single quotes
// SyntaxError: Unexpected token ILLEGAL

上面代码中,双引号字符串中是一个单引号字符串,因为单引号字符串不符合 JSON 格式,所以报错。

为了处理解析错误,可以将JSON.parse()方法放在try...catch代码块中。

try {JSON.parse("'String'");
} catch(e) {console.log('parsing error');
}

JSON.parse()方法可以接受一个处理函数,作为第二个参数,用法与JSON.stringify()方法类似。

function f(key, value) {if (key === 'a') {return value + 10;}return value;
}JSON.parse('{"a": 1, "b": 2}', f)
// {a: 11, b: 2}

上面代码中,JSON.parse()的第二个参数是一个函数,如果键名是a,该函数会将键值加上10。

JSON.parse()和JSON.stringify()可以结合使用,像下面这样写,实现对象的深拷贝。

JSON.parse(JSON.stringify(obj))

上面这种写法,可以深度克隆一个对象,但是对象内部不能有 JSON

不允许的数据类型,比如函数、正则对象、日期对象等。

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

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

相关文章

C#设置winform窗体自动适应不同分辨率的电脑

C#设置winform窗体自动适应不同分辨率的电脑 文章已被社区收录 加入社区 问题背景: 用winform开发了一个上位机软件,本机的台式开发电脑是宽屏的,上位机软件的显示效果良好,而在笔记本电脑上使用上位机软件时,出现了界…

计算机网络 (55)流失存储音频/视频

一、定义与特点 定义:流式存储音频/视频是指经过压缩并存储在服务器上的多媒体文件,客户端可以通过互联网边下载边播放这些文件,也称为音频/视频点播。 特点: 边下载边播放:用户无需等待整个文件下载完成即可开始播放…

Oracle存储过程语法详解

简介 存储过程是一系列SQL语句的集合,可以封装复杂的逻辑,实现特定的功能,可以提高执行速度和代码的复用性,预先编译后存储在数据库中,可以通过指定存储过程的名称对其进行调用。 本文主要讲解Oracle存储过程语法&am…

kafka-保姆级配置说明(broker)

一. important ##broker ID,cluster唯一标识,数字类型 ##此值可以不指定,有集群自动创建(由当前集群现有的brokerID 1)。 ##默认值为-1 broker.id5 #broker.id.generation.enabletrue ##zookeeper连接地址 zookeeper.…

推箱子游戏

java小游戏2 一游戏介绍 二图像准备 墙、箱子、人、箱子目的地,人左边、人右边、人上边、人下边 三结构准备 地图是什么,我们把地图想象成一个网格,每个格子就是工人每次移动的步长,也是箱子移动的距离,设置一个二维数…

如何分辨ddos攻击和cc攻击?

DDoS(分布式拒绝服务)攻击和 CC(Challenge Collapsar)攻击都属于网络攻击手段,主要通过消耗目标服务器资源使其无法正常提供服务,但它们在攻击原理、攻击特征等方面存在区别: 攻击原理 DDoS 攻…

期权帮|如何利用股指期货进行对冲套利?

锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 如何利用股指期货进行对冲套利? 对冲就是通过股指期货来平衡投资组合的风险。它分为正向与反向两种策略: (1)正向对冲&#xff…

软件质量与测试报告5-压力测试 JMeter 与 Badboy

A.百度搜索引擎压力测试 通过在Badboy下执行如下的测试场景来生成压力测试的脚本: a) 在Badboy的地址栏里面输入www.baidu.com,回车; b) 在右下区域打开的百度的主页上输入搜索关键字JMeter,回车; c) 在…

每日一题 417. 太平洋大西洋水流问题

417. 太平洋大西洋水流问题 代码使用队列进行广度搜索&#xff0c;分别遍历太平洋 和大西洋的河流&#xff0c;取交集。 class Solution { public:vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {set<pair<int,int&…

Java设计模式 九 桥接模式 (Bridge Pattern)

桥接模式 (Bridge Pattern) 桥接模式是一种结构型设计模式&#xff0c;它的核心思想是将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。这种模式通过组合而不是继承的方式来扩展功能&#xff0c;从而减少类之间的耦合度。 1. 模式结构 桥接模式的结构包括以下角色&…

USB——cherry 键盘分析

文章目录 cherry USB 键盘分析描述符结构设备描述符配置描述符集合配置描述符接口 1 描述符HID 描述符端点 IN 描述符接口 2 描述符HID 描述符端点 IN 描述符端点 OUT 描述符字符串描述符语言 ID (字符串索引为 0)厂商字符串(字符串索引为 1)产品字符串(字符串索引为 2)HID 报告…

关于自动控制原理中三阶系统瞬态响应与稳定性实验的研究报告

一、引言 1.1 研究背景与意义 自动控制原理作为现代工业生产、航空航天、智能交通等众多领域的关键理论基础&#xff0c;对提高生产效率、提升产品质量以及保障系统安全稳定运行起着举足轻重的作用。在实际应用中&#xff0c;自动控制系统能够根据预设的目标和反馈信息&#…

Mybatis多条件查询:Map传参与对象传参解析

Mybatis 多条件查询常见且关键&#xff0c;本文探讨两种方法——Map 传参和 Java Bean 对象传参&#xff0c;展示用法及区别&#xff0c;总结应用场景和优缺点。 1. Map传参方式 原理&#xff1a;Mybatis允许我们通过一个Map对象来传递动态SQL中的参数。Map的键对应于SQL语句中…

vue2和vue3组件之间的通信方式差异

Vue2 vs Vue3 组件通信方法对比 1. 父子组件通信 1.1 Props 传递 Vue2 <!-- 父组件 --> <template><child-component :message"message"></child-component> </template><script> export default {data() {return {message:…

wangEditor富文本编辑器,Laravel上传图片配置和使用

文章目录 前言步骤1. 构造好前端模版2. 搭建后端存储3. 调试 前言 由于最近写项目需要使用富文本编辑器&#xff0c;使用的是VUE3.0版本所以很多不兼容&#xff0c;实际测试以后推荐使用wangEditor 步骤 构造好前端模版搭建后端存储调试 1. 构造好前端模版 安装模版 模版安…

RedisTemplate和Redisson的使用和区别

文章目录 一. 数据缓存1.1 **为什么要用缓存**1.2 缓存的实现1.3 Redis1.4 Redis 数据结构1.5 实现方式1.6 对比1.7 实现定时预热缓存1.7.1 什么是热缓存1.7.2 什么时候用缓存预热1.7.3 缓存预热带来的问题1.7.4 怎么实现缓存预热1.7.5 预热缓存的注意点1.7.6 缓存预热 - 定时任…

程朱理学基本知识

文章目录 一、儒家兴起和衰落周期二、程颐和程颢三、朱熹四、程朱理学和女性改嫁 理学根本特点就是将儒家的社会、民族及伦理道德和个人生命信仰理念&#xff0c;构成更加完整的概念化及系统化的哲学及信仰体系&#xff0c;并使其逻辑化&#xff0c;心性化、抽象化和真理化。这…

kotlin 简介

Kotlin 是一种现代化、跨平台的编程语言&#xff0c;由 JetBrains 开发&#xff0c;并于 2011 年首次发布。它可以用于多种开发场景&#xff0c;包括 Android 应用开发、后端服务开发、Web 开发&#xff0c;以及跨平台应用开发。 以下是对 Kotlin 的核心介绍&#xff1a; Kotl…

three.js+WebGL踩坑经验合集(2):3D场景被相机裁切后,被裁切的部分依然可以被鼠标碰撞检测得到(射线检测)

three.js内置了Raycaster类实现鼠标的碰撞检测&#xff0c;用它可以实现3D物体的鼠标点击&#xff0c;移入移出&#xff0c;触屏检测一类的业务功能。 该功能虽然强大&#xff0c;但同事们普遍反映不是那么好用&#xff0c;因为它不像其它配套了可视编辑的3D引擎一样&#xff…

Spring Boot spring.factories文件详细说明

优质博文&#xff1a;IT-BLOG-CN 前言&#xff1a;经常看到 spring.factories 文件&#xff0c;却没有对它进行深入的了解和分析&#xff0c;今天我们就一起揭开面纱看看它的内在。 spring.factories 文件是 Spring Boot 自动配置机制的核心部分之一。它位于每个 Spring Boo…