JSON序列化与反序列化

一、序列化与反序列化的概念

序列化(Serialization):将数据结构或是对象 转换为 二进制串(字节序列)的过程

反序列化:将二进制串(字节序列)转换为 数据结构或者对象 的过程

序列化 就是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(如硬盘)。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

二、对象序列化的用途目的:

1、把对象的字节序列永久保存在硬盘上(以某种储存方式使自定义对象持久化);

2、在网络上传送对象的二进制序列(将对象从一个地方传递到另一个地方);

3、使程序更具维护性。

三、解析与序列化

早期的JSON解析器使用的是JavaScript函数的eval( ) 函数。由于JSON是JS语法的子集,所以eval()函数可以解析、解释并返回JS对象和数组。

由于在一些较早版本的浏览器,使用eval()对JSON数据结构存在风险,可能会产生一些恶意代码,所以现在不再经常使用这个函数。

JSON对象有两个方法:(在最简单的情况下)

JSON.stringify() 把JavaScript对象序列转换为JSON字符串;

JSON.parse() 将JSON字符串解析为原生Javascript对象;

实例:

在这个例子中使用JSON.stringify( ) 把JavaScript对象序列转换为一个JSON字符串

然后将其保存在jsonText变量中,并使用document.write( ) 函数使结果在页面输出。

var person= { 
               "name":"张三",
           "address":["中国","河北"],
           "age":"20",
        "gender":"男" ,
           "birth":"1999"
    };
    var jsonText = JSON.stringify(person);
document.write(jsonText);

显示结果

注意:在序列化JavaScript对象时,所有的函数及原形成员都会被有意忽略,默认情况下JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进;,不体现在结果中。此外,值为Undefined的任何属性也都会被跳过。最终结果中都是值为有效JSON数据类型的实例属性。

2、将JSON字符串直接传递给JSON.parse( ) 就可以得到相应的JavaScript值

例如,使用以下代码就会创建于person类似的对象。

 注意:虽然person和persoinf 具有相同的属性,但是它们是两个独立的、没有任何关系的对象。如果传递给 JSON.parse()不是有效的JSON,该方法就会出错

四、序列化选项

实际上,JSON.stringify()除了要序列化的javascript对象之外,还可以接收两个参数,这两个参数可以用于指定以不同方式序列化的JavaScript

1、第一个参数是过滤器(可为数组或函数

2、第二个参数是一个选项(表示是否在JSON字符串中保留缩进

 

(一)过滤结果

1、如果过滤器的参数是数组那么JSON.stringify( ) 的结果中将只包含数组中列出的属性

例如:

var person= { 
               "name":"张三 李四",
           "address":["中国","河北"],
           "age":20,
        "gender":"男" ,
           "birth":"1999"
    };
    var jsonText = JSON.stringify(person,["name","age"]);
    document.write(jsonText);

JSON.stringify( ) 的第一个参数是变量名称,第二个参数是一个数组,其中包含两个字符串:"name" 和 "age" 。这两个属性与将要序列化的对象中的属性是对应的,因此在返回结果的字符串中就会包含这两个属性:

2、如果第二个参数是函数,行为会稍有些不同。传入的函数接受两个参数,属性(键)名和属性值。根据属性名(键)可以知道应该如何处理要序列化的对象的属性。

属性名只能是字符串,而在值并非键值对结构的值时,键名可以是空字符串。

为了改变序列化对象的结果,函数返回的值就是相应键的值。

注意:如果函数返回了undefined,那么相应的属性会被忽略

var person= { 
               "name":"张三",
           "address":["中国 河北"],
           "age":20,
        "gender":"男" ,
           "birth":1999
    };
    var jsonText = JSON.stringify(person, function(key, value) {
        switch(key){
            case "address":
                return value.join(",")
            case "birth":
                return 2000;
            case "age":
                return undefined;
            default:
                return value;
        }
    });
    document.write(jsonText);

函数过滤器根据传入的键来决定结果。

如果键(属性名)为 "adress",则将数组连接为一个字符串;

如果键为 "birth",则将其值设置为2000;

如果键为 "age",通过返回undefined来删除该属性。

最后,一定要提供default项,此时返回传入的值,以便其他的值都可以正常出现在结果中。实际上,第一次调用这个函数过滤器,传入的键是一个空字符串,而值就是person 对象。

序列化后的字符串如下所示:

要序列化的对象中每一个对象都要经过过滤器,因此数组中的每个带都有这些属性的对象经过过滤器之后,每个对象都会包含"name"、"address"、"gender"、"birth" 属性。

 

(二)字符串缩进

JSON.stringify() 方法的第三个参数用于控制结果中的缩进和空白字符。

如果这个参数是一个数值,那他表示的是每个级别缩进的空格数。

实例:

1、要在每个级别中缩进5个空格

var person= { 
               "name":"张三",
           "address":["中国 河北"],
           "age":20,
        "gender":"男" ,
           "birth":1999
    };
    var jsonText = JSON.stringify(person, null,5);
    document.write(jsonText);

保存在jsonText中的字符串如下:

注意:JSON.stringify()也在结果字符中穿插了换行符以提高可读性。只要传入有效的控制缩进的参数值。最大缩进空格数为10,所有大于10的值都会自动转换为10。

2、如果缩进参数是一个字符串而并非数值,则这个字符串将在JSON中被用作缩进符(不再使用空格)。

在使用字符串的情况下,可以将缩进字符设置为制表符,或是两个短线之类任意字符。

注意:缩进符最长不超过10个字符。如果超过了10个字符长,结果中就会只显示出前10个的字符

 

 

 

(三)toJSON( ) 方法

有时候JSON.stringify() 方法不能满足对某些对象自定义序列化的需求。

这时,可以给对象定义toJSON( ) 方法,返回其自身的JSON数据格式

原生Date对象有一个toJSON()方法,能将JavaScript的Date对象自动转换为ISO 8601日期字符串(与在Date对象上调用toISOString()的结果完全一样)

可以为任何对象添加  toJSON( ) 方法。

实例:

var person= { 
               "name":"张三",
           "address":["中国 河北"],
           "age":20,
        "gender":"男" ,
           "birth":1999,
           toJSON: function(){
               return person.address;
               // return this.address;
           }
    };
    var jsonText = JSON.stringify(person);
    console.log(jsonText);

person对象上定义了一个toJSON( ) 方法,该方法返回 person 的 address 地址。这个对象可以被序列化为一个简单的字符串而非对象。

可以让toJSON()方法返回任何值,都可以正常工作。

假设,想让方法返回 undefined ,此时如果包含它的对象嵌套在另一个对象中,会导致它的值变成null,如果是顶级对象,则结果就是undefined。

 

(四)序列化对象的顺序

 假设把一个对象传入JSON.stringify( )序列化该对象的顺序如下

1、如果存在 toJSON( ) 方法并且可以通过方法获得有效的值,则调用该方法,否则返回对象本身;

2、如果提供了第二个参数,应用这个函数过渡器。传入函数过渡器的值是第一步返回的值;

3、对第二步返回的每个值进行相应的序列化;

4、如果提供了第三个函数,执行相应的格式化;

无论是考虑定义toJSON( ) 方法,还是使用函数过滤器,又或者是同时使用着两种方法,理清顺序都是非常重要的。

五、解析选项

 JSON.parse( ) 方法也可以接收另一个参数,该参数是一个函数,将在每个键值对上调用——还原函数

为了区别JSON.stringify()接收的替换(过渡)函数(replacer),这个函数被称之为还原函数(reviver)

注意:如果还原函数 undefined ,则表示要从结果中删除相应的键。如果返回其他值,则将该值插入到结果中

实例:

var person= { 
               "name":"张三",
           "address":["中国 河北"],
           "age":20,
        "gender":"男" ,
           "birth":1999,
           "releaseDate":new Date(2019, 9, 29)    
    };
    var jsonText = JSON.stringify(person);
    var jsonCopy = JSON.parse(jsonText, function(key, value){
        if (key == "releaseDate") {
            return new Date(value);
        } 
        else{
            reture value;
        }
    });
    console.log(jsonCopy.releaseDate.getFullYear());

      在这个例子中,先是为person对象增加了一个releaseDate属性,该属性又保存了一个Date对象。

这个对象经过序列化之后变成了有效的JSON字符串,然后经过解析又在jsonCopy中还原为一个Date对象。

还原数据在遇到 "releaseDate" 键时,会基于相应的值创造一个新的Date对象。

结果就是jsonCopy.releaseDate 属性中会保存一个Date 对象。正因为如此,才能基于这个对象调动 getFullYear( ) 方法。

原文地址:https://www.cnblogs.com/nyw1983/p/11605241.html