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( ) 方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM