在之前的web开发中
,咱们多数选择纯文本
或XML
做为咱们的提交的数据格式,大多数是XML
,少数纯文本
。其实从AJAX(Asynchronous JavaScript and XML)
的命名咱们也知道,数据交换是大多数经过XML
格式进行的。可是XML
格式有一个缺点,就是文档构造复杂,须要传输比较多的字节数,而且解析起来也比较麻烦。因此就建立了JSON
这种数据描述格式,能够很简单的就描述很复杂的数据。同时独立于语言,这样就能够在多种语言内使用。也正是由于这个,JSON
的轻便性逐渐获得重视,后来替代XML
成为最主要的数据传输格式。javascript
ps: 固然,虽说了不少
JSON
的好处,你就觉得不用学习XML
了吗?确定不是啦,微信公共平台接口中的有是有至关一部分接口使用了XML
的。html
JSON
对象包含两个方法: 用于解析 JavaScript Object Notation (JSON) 的 parse() 方法,以及将对象/值转换为 JSON 字符串的 stringify() 方法。除了这两个方法, JSON 这个对象自己并无其余做用,也不能被调用或者做为构造函数调用。java
ps: JSON:并非 JavaScript 的子集。尽管不是严格意义上的子集,JSON 很是接近 JavaScript 语法的子集。web
JavaScript类型 | JSON 的不一样点 |
---|---|
对象和数组 | 属性名称必须是双引号括起来的字符串;最后一个属性后不能有逗号。 |
数值 | 禁止出现前导零(JSON.stringify 方法自动忽略前导零,而在 JSON.parse 方法中将会抛出 SyntaxError);若是有小数点, 则后面至少跟着一位数字。 |
针对于这两点,咱们举个例子,对于对象和数组类型:json
// 属性名称必须是双引号括起来的字符串 const test1 = "['1','1']" JSON.parse(test1) // Uncaught SyntaxError: Unexpected token ' in JSON at position 1 const test2 = "{'name':'gating'}" JSON.parse(test2) // Uncaught SyntaxError: Unexpected token o in JSON at position 1 const test3 = '["2","1"]' JSON.parse(test3) // ["2","1"] const test4 = '{"name":"gating"}' JSON.parse(test3) // {name: "gating"} // 最后一个属性后不能有逗号 const test5 = '["2","1",]' JSON.parse(test5) // Uncaught SyntaxError: Unexpected token ] in JSON at position 9 const test6 = '{"name":"gating",}' JSON.parse(test6) // Uncaught SyntaxError: Unexpected token } in JSON at position 17
对于数值类型:数组
// 禁止出现前导零 const test7 = [00010, 1] JSON.stringify(test7) // "[8,1]" const test8 = "[00010, 1]" JSON.parse(test8) // SyntaxError: Unexpected number in JSON at position 2** // 若是有小数点,则后面至少跟着一位数字。 const test9 = [1, 1.] JSON.stringify(test9) // "[1,1]" const test10 = "[1, 1.]" JSON.parse(test10) // Uncaught SyntaxError: Unexpected token ] in JSON at position 6
ps: 0+数字表示8进制,- -因此上面打印出来的是8,一样的有:0b+数字(二进制)、0x+数字(16进制),其实0o+数字也能够表示8进制微信
其实还有一个字符串类型,JavaScript和JSON处理是不一致的,这里为啥我只写两点呢?是由于还有如今在新版的Chrome已经能够解析正常,可是想具体能够查看下面参考连接自行了解,这里就不展开了less
参考:JavaScript 与 JSON 的区别,字符串那一点我在Chrome 85.0.4183.83以及能够正常解析函数
stringify() 方法用于将JavaScript
值转换为JSON
字符串。学习
虽然咱们常常用这个方法,但我想估计有很多人不知道它竟然有三个参数之多吧?分别是value
、replacer
、space
。
JSON.stringify(value[, replacer [, space]])
可选
可选
一般咱们最经常使用的就是第一个参数,也就是value参数,可是你知道它的运算规则是怎么样的吗?闲话很少说,直接上例子
JSON.stringify([NaN, Infinity, null]) // [null,null,null]
JSON.stringify({x: undefined, y: Object, z: Symbol("")}) // "{}"
JSON.stringify([undefined, Object, Symbol("")]) // "[null,null,null]"
JSON.stringify(undefined) // undefined JSON.stringify(Object) // undefined JSON.stringify(Symbol("")) // undefined
JSON.stringify({[Symbol("foo")]: "foo"}) // "{}" JSON.stringify({[Symbol.for("foo")]: "foo"}, [Symbol.for("foo")]) // "{}"
JSON.stringify({ toJSON: function() { return 'gating' } }) // "gating" const name = { age: 18, toJSON: function () { return 'gating' }, } JSON.stringify({ name }) // {"name":"gating"}
又由于Date对象上挂载了一个toJSON方法,因此针对于Date类型,它默认就会调用Date类型上的toJSON方法(同Date.toISOString())
JSON.stringify(new Date("2020/01/01")) // "2019-12-31T16:00:00.000Z" 由于中国在东八区,因此相差了8小时
ps: 东八区(UTC/GMT+08:00)是比世界协调时间(UTC)/格林尼治时间(GMT)快8小时的时区
JSON.stringify( Object.create(null, { x: { value: 'x'}, // enumerable 默认为不可枚举 y: { value: 'y', enumerable: true }, }) ) // "{"y":"y"}" const map = new Map() Object.defineProperty(map, 'name', { value: 'gating', enumerable: true }) Object.defineProperty(map, 'age', { value: 18 }) JSON.stringify(map) // {"name":"gating"} JSON.stringify(new Set) // {} JSON.stringify(new RegExp) // {}
看到这里,你基本已经知道运算规则是怎么样滴了,也就知道了为何JSON.stringify + JSON.parse
不能转换函数、正则、Error等对象了吧?
那么接下来就要了解下更有意思的东西啦,就是stringify
第二个参数replacer
啦
replacer 参数能够用来来更改默认的字符串化的行为。它能够是一个函数或者一个数组。若是该参数为 null 或者未提供,则对象全部的属性都会被序列化。
在开始时, replacer 函数会被传入一个空字符串做为 key 值,表明着要被 stringify 的这个对象。随后每一个对象或数组上的属性会被依次传入。
这句话看不太懂?没关系,举个例子你就懂了
function replacer(key, value) { console.log('[' + key + ']:' + value) return value } JSON.stringify({ name: 'gating', age: 18 }, replacer) // []:[object Object] // [name]:gating // [age]:18
上面例子中,他会执行三次,也就是一开始他会默认传一个空字符串做为键,而键值是整个对象;第二次键为name
,键值为gating
,以此类推。
固然,这里也有个特别须要注意的点,就是返回的是一个对象的时候,该对象递归地序列化成 JSON 字符串,对每一个属性调用replacer
方法。除非该对象是一个函数,这种状况将不会被序列化成 JSON 字符串。
好比:
function replacer(key, value) { return {a:1} } JSON.stringify({}, replacer)
由于咱们每次返回的都是对象,那么每次都会调用replacer
,因此会形成堆栈溢出,那么咱们举个不会溢出的小栗子例子吧🤣:
function replacer(key, value) { if(typeof value === 'object'){ return { age: 9 } } return value * 2 } const name = {} JSON.stringify(name, replacer) // {"age":18}
在这里,每一次处理的对象,都是前一次返回的值。由于咱们replacer
修改了name
对象,接着就要递归replacer
处理修改后的对象。
总结:递归处理中,每一次处理的对象,都是前一次返回的值。
function f(key, value){ console.log(value) if (typeof value === "object"){ return {b: 2}; } return value*2; } JSON.stringify(o,f)
那么,既然是更改默认的字符串化的行为,那么我就尝试下更改下吧
function replacer(key, value) { if (typeof value === "number") { return value * 2; } return value; } const me = { name: 'gating', age: 9, } JSON.stringify(me, replacer) // {"name":"gating","age":18}
function replacer(key, value) { if (typeof value === "string") { return undefined; } return value; } const me = { name: 'gating', age: 18, } JSON.stringify(me, replacer) // {"age":18} 剔除了name属性 JSON.stringify([1,"2"], replacer) // "[1,null]"
注意: 不能用 replacer 方法,从数组中移除值(values),如若返回 undefined 或者一个函数,将会被 null 取代(其实从 value 的运算规则咱们也知道会出现这个结果了)。
数组的值表明将被序列化成JSON
字符串的属性名
const me = { name: 'gating', age: 18, } JSON.stringify(me, ['name']) // {"name":"gating"} 只保留了name的属性值 JSON.stringify(['a', 'b'], ['0']) // ['a', 'b']
这个相似白名单的数组,只对对象的属性有效,对数组无效。
space 参数用来控制结果字符串里面的间距,增长返回的 JSON 字符串的可读性。若是是一个数字, 则在字符串化时每一级别会比上一级别缩进多这个数字值的空格(最多10个空格);若是是一个字符串,则每一级别会比上一级别多缩进该字符串(或该字符串的前10个字符)。
JSON.stringify({ name: "gating", age: 18 }, null, 6) /* "{ "name": "gating", "age": 18 }" */
JSON.stringify({ name: "gating", age: 18 }, null, '|-') /* "{ |-"name": "gating", |-"age": 18 }" */
由于最用用到要美化JSON的场景,因此顺便把制表符也写出来了 😊
就是提交的时候是json,返回的时候美化json显示到输入框内
JSON.stringify({ name: "gating", age: 18 }, null, '\t') /* "{ "name": "gating", "age": 18 }" */
parse() 方法用于将一个 JSON 字符串转换为对象。
JSON.parse(text[, reviver])
text参数没啥可说的,就是要被解析成 JavaScript 值的字符串,必须符合JSON的语法格式
JSON.parse('{}') // {} // 若是传入的字符串不是有效的 JSON 格式, JSON.parse方法将报错。 JSON.parse("'String'") // Uncaught SyntaxError: Unexpected token ' in JSON at position 0
reviver参数和JSON.stringify方法的reviver参数相似,惟一不一样的是若是有深层对象,他的遍历顺序依照:
从最内层开始,按照层级顺序,依次向外遍历,而JSON.stringify的遍历顺序恰好相反,从外向内
JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (k, v) { console.log(k); // 输出当前的属性名,从而得知遍历顺序是从内向外的, // 最后一个属性名会是个空字符串。 return v; // 返回原始属性值,至关于没有传递 reviver 参数。 }) // 1 2 4 6 5 3 "" JSON.stringify({"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}, function (k, v) { console.log(k); return v; }) // "" 1 2 3 4 5 6
虽然本文罗嗦了点,但仍是感谢各位观众老爷的能看到最后 O(∩_∩)O 但愿你能有所收获 😁