说说JSON

144 阅读7分钟

一直都在用JSON.stringify()和JSON.parse(),但是从来没有去留意过一些细节内容,上礼拜面试的时候做笔试题,让我写JSON.stringify的返回值,直接给我打懵了,回来赶紧补了一下知识黑洞,现在总结一下,如果有什么不对的地方,欢迎大家指出

一、什么是JSON

JSON 是一种按照 JavaScript 对象语法的数据格式,这是 Douglas Crockford 推广的。虽然它是基于 JavaScript 语法,但它独立于 JavaScript

---MDN

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它以易于阅读和编写的文本格式表示结构化数据。它基于JavaScript语言的一个子集,但现在已经成为一种独立于编程语言的通用数据格式

二、JSON的用途

JSON 可以作为一个对象或者字符串存在,前者用于解读 JSON 中的数据,后者用于通过网络传输 JSON 数据。

---MDN

  1. 数据传输:JSON常用于客户端和服务器之间的数据传输。通过将数据转换为JSON格式,可以方便地在网络上进行传输,并且可以被各种编程语言和平台解析和处理。
  2. 配置文件:JSON格式可以用于存储和传输配置信息。许多应用程序使用JSON格式来保存各种配置选项,例如Web应用程序的配置文件、软件的设置文件等。
  3. API数据交换:在Web开发中,许多API(Application Programming Interface)使用JSON格式作为数据交换的标准。当客户端向服务器请求数据或发送数据时,通常使用JSON格式来表示请求和响应的数据。
  4. 存储和持久化:JSON格式可以用于将数据存储到数据库或文件中。许多数据库系统支持将JSON格式作为数据类型或存储格式,使得可以方便地将结构化数据以JSON形式进行存储和检索。
  5. 配置数据传递:JSON格式可以用于在不同组件之间传递配置信息。例如,在微服务架构中,各个微服务之间可以使用JSON格式来传递配置信息,以实现松耦合和灵活性。

三、JSON的书写规则

  1. 数据类型:JSON支持以下数据类型:

    • 字符串(使用双引号括起来):"Hello World"
    • 数字:42
    • 布尔值:true 或 false
    • 数组(使用方括号括起来):[1, 2, 3]
    • 对象(使用花括号括起来):{"name": "John", "age": 30}
    • null
  2. 键值对:JSON使用键值对的方式来表示数据。键是一个字符串,值可以是任何合法的JSON数据类型。键和值之间使用逗号(,)分隔,最后一个键值对不能有(,)

    示例:

    {"name": "John", "age": 30}
    
  3. 对象:JSON对象由一对花括号({})包围,里面包含零个或多个键值对。键值对之间使用逗号(,)分隔,。

    示例:

    {
      "name": "John",
      "age": 30,
      "isStudent": true
    }
    
  4. 数组:JSON数组由一对方括号([])包围,里面包含零个或多个值。值之间使用逗号(,)分隔。

    示例:

    [1, 2, 3, 4]
    
  5. 嵌套:JSON数据可以嵌套使用,可以在一个JSON对象中嵌套另一个JSON对象或数组。

    示例:

    {
      "name": "John",
      "age": 30,
      "hobbies": ["reading", "running"],
      "address": {
        "street": "123 Main St",
        "city": "New York"
      }
    }
    
  6. 注释:JSON本身不支持注释,因为它是一种数据交换格式而不是编程语言。

四、JSON.stringify()

作用:将一个js对象转为JSON字符串

语法:JSON.stringify(value[, replacer [, space]])

value(可选):要转换的js对象,可不填写

console.log(JSON.stringify()) //不会报错 输出undefined

replacer(可选):

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

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

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

let obj={
    a:1,
    b:'2'
 }
console.log(JSON.stringify(obj,(key,value)=>{
    if(key==='a'){
        return value+10
    }
    return value
},3))
console.log(JSON.stringify(obj,['a'],3))

输出结果:

image.png

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

1、如果参数是个数字,它代表有多少的空格;上限为 10。该值若小于 1,则意味着没有空格;

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

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

示例:

let obj={
    a:1,
    b:'2'
 }
 console.log(JSON.stringify(obj.null,3))
 console.log(JSON.stringify(obj,null,'1234'))
 console.log(JSON.stringify(obj,null,'1234567890123'))

输出结果:

image.png

JSON.stringfy()的转换规则

  1. 见人说人话,见鬼说鬼话的undefined、Symbol、function
  • undefined、Symbol、function在非数组对象中---被忽略
let obj={
      a:undefined,
      b:function(){},
      c:Symbol()
    }
console.log('非数组对象中:',JSON.stringify(obj)) // 非数组对象中:{}
  • undefined、Symbol、function在数组中---转为null
let arr = [undefined,function(){},Symbol()]
console.log(‘’数组中,JSON.stringify(arr)) //数组中:[null,null,null]
  • undefined、Symbol、function单独使用---转为undefined
let a = undefined
console.log('单独的undefined:',JSON.stringify(a)) // 单独的undefined: undefined

let b = function(){}
console.log('单独的function:',JSON.stringify(b)) // 单独的undefined: undefined

let c = Symbol()
console.log('单独的Symbol:',JSON.stringify(c)) //单独的JSON.stringify(a)JSON.stringify(a)Symbol: undefined

2.Boolean、Number、String---统一转为原始值

let b = new Boolean(true) 
console.log(JSON.stringify(b))   // true
console.log(JSON.stringify([b])) // [true]
console.log(JSON.stringify({b})) // {"b":true}

let n = new Number(7)
console.log(JSON.stringify(n))   // 7
console.log(JSON.stringify([n])) // [7]
console.log(JSON.stringify({n})) // {"n":7}

let s = new String('xf')
console.log(JSON.stringify(s))   // "xf"
console.log(JSON.stringify([s])) // ["xf"]
console.log(JSON.stringify({s})) // {"s":"xf"}

3.Symbol作为key---被忽略(即便 replacer 参数中强制指定包含了它们)

let obj={
    [Symbol()]:'symbol key'
}
console.log(JSON.stringify(obj)) // {}

let arr=[]
arr[Symbol()] = 7
console.log(arr)                 //  [ [Symbol()]: 7 ]
console.log(JSON.stringify(arr)) //  []

4.NaN、Infinity、null---统一转为null

let a=NaN
console.log(JSON.stringify(a))   // null
console.log(JSON.stringify([a])) // [null]
console.log(JSON.stringify({a})) // {"a":null}

let b=Infinity
console.log(JSON.stringify(b))   // null
console.log(JSON.stringify([b])) // [null]
console.log(JSON.stringify({b})) // {"b":null}

let c=null
console.log(JSON.stringify(c))   // null
console.log(JSON.stringify([c])) // [null]
console.log(JSON.stringify({c})) // {"c":null}

5.Date---统一转为字符串(调用了 toJSON())

let time=new Date()
console.log(JSON.stringify(time))   // "2023-06-01T15:32:04.436Z"
console.log(JSON.stringify([time])) // ["2023-06-01T15:32:04.436Z"]
console.log(JSON.stringify({time})) // {"time":"2023-06-01T15:32:04.436Z"}

6.有toJSON()方法--- 调用toJSON()后的返回值被序列化

let obj={
    a:1,
    b:'2',
    toJSON:()=>{
        return {
            c:1,
            d:'2'
        }
    }
}
console.log(JSON.stringify(obj)) // {"c":1,"d":"2"}

7、仅序列化可枚举属性

let obj=Object.create(null,
    {
        a:{
            value:'a',enumerable:true
        },
        b:{
            value:'b',enumerable:false
        }
    }
)
console.log(JSON.stringify(obj)) // {"a":"a"}

8、循环引用---报错

let obj1={}
let obj2={}
obj1.prop=obj2
obj2.prop1 = obj1
console.log(JSON.stringify(obj1)) // TypeError: Converting circular structure to JSON

9、BigInt---报错

let b = 10n
console.log(typeof b)          // bigint
console.log(JSON.stringify(b)) //TypeError: Do not know how to serialize a BigInt

总结:

1、undefined、function、Symbol,在非数组对象中--被忽略,在数组中--null,单独使用时--undefined

2、布尔、数字、字符串的包装对象--原始值

3、Symbol作为key---被忽略

4、NaN、Infinity、null--null

5、Date--字符串

6、有toJSON()--toJSON()的返回值被序列化

7、仅序列化可枚举属性

8、存在循环引用-- 报错

9、存在bigInt类型--报错

五、JSON.parse()

作用:解析JSON字符串

语法:JSON.parse(text[, reviver])

text(必填):要被解析成js值的字符串,缺少该参数直接报错

reviver(可选):转换器,如果传入该参数 (函数),可以用来修改解析生成的原始值,调用时机在 parse 函数返回之前,解析值和text按照从最里层开始的顺序去调用本函数,本函数若返回undefined,则删除该属性,本函数的两个参数(key,value)表示属性值和属性名称,当解析到最外层(解析值text)时,key为‘’

let jsonStr='{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}'
let obj = JSON.parse(jsonStr,(k,v)=>{
    console.log('key',k)
    if(k===''){
        return v
    }
    return v*10
})
console.log(obj)

输出结果:

image.png

六、自测环节

好了,知识点都罗列完毕了,最后来一道题检验一下自己的学习成果吧

let obj={
    a:1,
    b:'2',
    c:true,
    d:null,
    e:undefined, 
    f:Symbol(), 
    g:function(){ 
        console.log('obj function')
    },
    h:[1,'2',true,null,undefined,Symbol(),function(){console.log('array function')}],
    i: new Boolean(false), 
    j:new Number(1),
    k:new String('k'), 
    l:NaN, 
    m:Infinity, 
    n:-Infinity, 
    o:{
        oo:12,
        toJSON:function(){
            return {name:'xf',age:14}
        }
    },
    p:new Date(), 
    [Symbol()]:2,
    q:new RegExp(),
    r:new Error()
}
let jsonStr = JSON.stringify(obj,null,2)
console.log(jsonStr)
console.log(JSON.stringify())
console.log(JSON.parse())

答案就不写出来了,注意哦,里面隐藏了两个没有在前面提到的对象,赶紧去试试他们会返回什么值吧