JSON
文章目錄
- JSON
- JSON 語法
- 簡單值
- 物件
- 陣列
- 決議和序列化
- JSON 物件
- 序列化選項
- 決議選項
- JSON 的優點
- ENDING
前言 : JavaScript 物件簡譜(JSON,JavaScript Object Notation)標準,JSON 是 JavaScript 的嚴格子集,利用 JavaScript 中的幾種模式來表示結構化資料,理解 JSON 最關鍵的一點是要把它當成一種資料格式,而不是編程語言,JSON 不屬于 JavaScript,它們只是擁有相同的語法而已,JSON也不是只能在 JavaScript 中使用,它是一種通用資料格式,很多語言都有決議和序列化 JSON 的內置能力,

JSON 語法
支持三種型別
- 簡單值 : 字串、數值、布林值和 null 可以在 JSON 中出現,就像在 JavaScript 中一樣,特殊值
undefined不可以 - 物件 : 第一種復雜資料型別,物件表示有序鍵/值對,每個值可以是簡單值,也可以是復雜型別,
- 陣列 : 第二種復雜資料型別,陣串列示可以通過數值索引訪問的值的有序串列,陣列的值可以是任意型別,包括簡單值、物件,甚至其他陣列,
注意 : JSON 沒有變數、函式或物件實體的概念,JSON 的所有記號都只為表示結構化資料,雖然它借用了JavaScript 的語法,但是千萬不要把它跟JavaScript 語言混淆,
簡單值
- 最簡單的 JSON 可以是一個數值,
- 舉個栗子 :
5"hello"
- 布林值和
null本身也是有效的 JSON 值,
- 舉個栗子 :
注意 : JavaScript 字串與 JSON 字串的主要區別是,JSON 字串必須使用雙引號(單引號會導致語法錯誤),
物件
-
物件使用與
JavaScript物件字面量略為不同的方式表示,-
以下是
JavaScript中的物件字面量: -
let object = { "name" : "Nicholas", "age" :29 }; -
而
JSON的表示物件語法是 -
{ "name": "Nicholas", "age": 29 }
-
-
與
JavaScript物件字面量相比,JSON主要有兩處不同,首先,沒有變數宣告(JSON中沒有變數),其次,最后沒有分號(不需要,因為不是JavaScript陳述句),同樣,用引號將屬性名包圍起來才是有效的JSON, -
JavaScript和JSON的屬性的值都可以是簡單值或復雜資料型別值,而JSON可以在物件中再嵌入物件,-
比如 :JSON資料
-
{ "name": "Nicholas", "age": 29, "school": { "name": "Merrimack College", "location": "North Andover, MA" } } -
上述例子中即使整個
JSON物件中有兩個屬性都叫 “name” ,但它們屬于兩個不同的物件,一個是外面物件的"name"屬性,另個是里面 “school” 物件的 “name” 屬性,因此是允許的,同一個物件中不允許出現兩個相同的屬性,
-
-
與
JavaScript不同,JSON中的物件屬性名必須始終帶雙引號,手動撰寫 JSON 時漏掉這些雙引號或使用單引號是常見錯誤,
陣列
-
JSON 的第二種復雜資料型別是陣列,
-
陣列在 JSON 中使用 JavaScript 的陣列字面量形式表示,
-
例如,以下是一個 JavaScript 陣列:
-
let values = [5,"哈嘍",false];
-
-
在 JSON 中可以使用類似語法表示相同的陣列:
-
[25, "hi", true]
-
-
同樣,JSON沒有變數,也沒有分號,陣列和物件可以組合使用,以表示更加復雜的資料結構
-
[ { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas", "Matt Frisbie" ], "edition": 4, "year": 2017 }, { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], "edition": 3, "year": 2011 }, { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], "edition": 2, "year": 2009 }, { "title": "Professional Ajax", "authors": [ "Nicholas C. Zakas", "Jeremy McPeak", "Joe Fawcett" ], "edition": 2, "year": 2008 }, { "title": "Professional Ajax", "authors": [ "Nicholas C. Zakas", "Jeremy McPeak", "Joe Fawcett" ], "edition": 1, "year": 2007 }, { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], "edition": 1, "year": 2006 } ]
-
-
物件和陣列通常會作為 JSON 陣列的頂級結構,以便創建大型復雜資料結構,
決議和序列化
JSON 的迅速流行并不僅僅因為其語法與 JavaScript 類似,很大程度上還因為 JSON 可以直接被決議成可用的 JavaScript 物件,與決議為 DOM 檔案的 XML 相比,這個優勢非常明顯,為此,JavaScript 開發者可以非常方便地使用 JSON 資料,
比如 : JSON資料中books陣列
[ { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas", "Matt Frisbie" ], "edition": 4, "year": 2017 }, { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], "edition": 3, "year": 2011 }, { "title": "Professional JavaScript", "authors": [ "Nicholas C. Zakas" ], "edition": 2, "year": 2009 } ]獲取第二本書的書名 :
books[1].title
JSON 物件
早期的
JSON決議器基本上就相當于JavaScript的 eval() 函式,因為JSON是JavaScript語法的子集,所以 eval() 可以決議、解釋,并將其作為JavaScript物件和陣列回傳,
-
JSON物件在JavaScript中有兩個方法 :stringify(): 將JavaScript序列化為JSON字串parse(): 將 JSON 決議為原生JavaScript值
-
舉個栗子 :
-
let book = { title: "Professional JavaScript", authors: [ "Nicholas C. Zakas", "Matt Frisbie" ], edition: 4, year: 2017 }; //JavaScript的物件 let jsonText = JSON.stringify(book); //將JavaScript物件序列化為JSON-
這個例子使用
JSON.stringify()把一個JavaScript物件序列化為一個JSON字串,保存在變數jsonText中, -
默認情況下,
JSON.stringify()會輸出不包含空格或縮進的 JSON 字串 -
變數
jsonText的內容 :-
{"title":"Professional JavaScript","authors":["Nicholas C. Zakas","Matt Frisbie"],"edition":4,"year":2017}
-
-
-
-
在序列化
JavaScript物件時,所有函式和原型成員都會有意地在結果中省略,此外,值為undefined的任何屬性也會被跳過,最終得到的就是所有實體屬性均為有效JSON資料型別的表示, -
JSON字串可以直接傳給JSON.parse(),然后得到相應的JavaScript值,-
比如,可以使用以下代碼創建與 book 物件類似的新物件:
-
let bookCopy = JSON.parse(jsonText); //將JSON決議為JavaScript的物件 -
注意,
book和bookCopy是兩個完全不同的物件,沒有任何關系,但是它們擁有相同的屬性和值, -
JSON.parse()傳入的JSON字串必須是有效的,如果傳入的 JSON 字串無效,則會導致拋出錯誤,
-
序列化選項
JavaScript中JSON.stringify()方法除了要序列化的物件,還可以接收兩個引數,- 這兩個引數可以用于指定其他序列化
JavaScript物件的方式,- 第一個引數是過濾器,可以是陣列或函式;第二個引數是用于縮進結果 JSON 字串的選項,
- 單獨或組合使用這些引數可以更好地控制 JSON 序列化,
- 過濾結果
-
如果第二個引數是一個陣列,那么
JSON.stringify()回傳的結果只會包含該陣列中列出的物件屬性,-
比如下面的例子:
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript序列化</title> </head> <body> <script> let book = { title: "富婆通訊錄", authors: [ "CS@zeny", "各大富婆" ], edition: 1, year: 2021 }; let jsonText1 = JSON.stringify(book, ["title", "edition"]); //將屬性"title"和"edition"序列化 let jsonText2 = JSON.stringify(book, ["title", "edition", "authors"]); //將屬性"title","edition"和"authors"序列化 document.write("jsonText1 : " + jsonText1); //輸出jsonText1的內容 document.write("<br>"); //換行 document.write("jsonText2 : " + jsonText2); //輸出jsonText2的內容 </script> </body> </html> -
得到的結果為
-
jsonText1 : {"title":"富婆通訊錄","edition":1} jsonText2 : {"title":"富婆通訊錄","edition":1,"authors":["CS@zeny","各大富婆"]}
-
-
如果第二個引數是一個函式,則行為又有不同,
-
提供的函式接收兩個引數:屬性名( key )和屬性值( value ),可以根據這個
key決定要對相應屬性執行什么操作,這個key始終是字串,只是在值不屬于某個鍵/值對時會是空字串, -
為了改變物件的序列化,回傳的值就是相應
key應該包含的結果,注意,回傳undefined會導致屬性被忽略, -
下面看一個例子:
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript序列化</title> </head> <body> <script> let book = { title: "富婆通訊錄", authors: [ "CS@zeny", "各大富婆" ], edition: 1, year: 2021, price:"100yuan" }; let jsonText = JSON.stringify(book, (key, value) => { switch (key) { case "authors": //如果鍵是"authors" return value.join(",") //則將陣列轉換成字串 case "year": //如果鍵是"year" return 5000; //則將value值置為5000 case "edition": //如果鍵是"edition" return undefined; //則將回傳 undefined, 回傳未定義則會忽略該屬性,即忽略"edition"屬性 default: return value; //最后一定要提供默認回傳值,以便回傳其他屬性傳入的值 } //函式基于鍵進行過濾 }); //第一次呼叫這個函式實際上會傳入空字串 key,值是 book 物件,這也解釋了為啥最后默認回傳值一定得是vaule,如果是其他則傳不進book物件. document.write(jsonText); //輸出jsonText的內容 </script> </body> </html> -
輸出結果 :
-
{"title":"富婆通訊錄","authors":"CS@zeny,各大富婆","year":5000,"price":"100yuan"}
-
-
注意,函式過濾器會應用到要序列化的物件所包含的所有物件,因此如果陣列中包含多個具有這些屬性的物件,則序列化之后每個物件都只會剩下上面這些屬性,
- 字串縮進
-
JSON.stringify()方法的第三個引數控制縮進和空格,在這個引數是數值時,表示每一級縮進的空格數, -
說明 : 如果第二個引數不需要填的話,就必須要用關鍵字
null來代替-
比如 :
let jsonText1 = JSON.stringify(book, null, 2); -
舉個大栗子 :
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript序列化</title> </head> <body> <script> let book = { title: "富婆通訊錄", authors: [ "CS@zeny", "各大富婆" ], edition: 1, year: 2021, price: "100yuan" }; let jsonText1 = JSON.stringify(book, null, 2); //每級縮進2個空格 let jsonText2 = JSON.stringify(book, null, 4); //每級縮進4個空格 console.log(jsonText1); //在控制臺輸出 console.log(jsonText2); //在控制臺輸出 //說明: 如果使用document.write(); 函式在網頁上輸出會看不到空格,因為在網頁上HTML語法直接忽略空格, 所以要用console.log()函式在控制臺輸出 </script> </body> </html> -
輸出效果 :
-

-
-
注意,除了縮進, JSON.stringify() 方法還為方便閱讀插入了換行符,這個行為對于所有有效的縮進引數都會發生,(只縮進不換行也沒什么用,)最大縮進值為 10,大于 10 的值會自動設定為 10,
-
如果縮進引數是一個字串而非數值,那么JSON字串中就會使用這個字串而不是空格來縮進,使用字串,也可以將縮進字符設定為
Tab或任意字符,-
如兩個連字符
--, 一個Tab -
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript序列化</title> </head> <body> <script> let book = { title: "富婆通訊錄", authors: [ "CS@zeny", "各大富婆" ], edition: 1, year: 2021, price: "100yuan" }; let jsonText1 = JSON.stringify(book, null, "--"); //每級縮進字串-- let jsonText2 = JSON.stringify(book, null, " "); //每級用Tab縮進, 注意引號內不是空格輸入而是按一次Tab鍵輸入 let jsonText3 = JSON.stringify(book, null, 4); //每級縮進4個空格 console.log(jsonText1); //在控制臺輸出 console.log(jsonText2); //在控制臺輸出 console.log(jsonText3); //在控制臺輸出 //說明: 如果使用document.write(); 函式在網頁上輸出會看不到空格,因為在網頁上HTML語法直接忽略了, 所以要用console.log()函式在控制臺輸出 </script> </body> </html> -
效果 :
-

注意 : 使用字串時同樣有 10 個字符的長度限制,如果字串長度超過 10,則會在第 10 個字符處截斷,
-
toJSON()方法
-
當物件需要在
JSON.stringify()之上自定義JSON序列化,此時,可以在要序列化的物件中添加toJSON()方法,序列化時會基于這個方法回傳適當的JSON表示, -
事實上,原生
Date物件就有一個toJSON()方法,能夠自動將JavaScript的Date物件轉換為 ISO 8601 日期字串(本質上與在Date 物件上呼叫toJSON()方法一樣), -
舉個栗子 :
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript序列化</title> </head> <body> <script> let book = { title: "富婆通訊錄", authors: [ "CS@zeny", "各大富婆" ], edition: 1, year: 2021, price: "100yuan", toJSON: function() { return this.title; } //這里 book 物件中定義的 toJSON() 方法簡單地回傳了圖書的書名( this.title ), }; let jsonText = JSON.stringify(book); console.log(jsonText); //在控制臺輸出 </script> </body> </html> -
輸出結果 :
"富婆通訊錄" -
toJSON()方法可以回傳任意序列化值,都可以起到相應的作用,如果物件被嵌入在另一個物件中,回傳undefined會導致值變成null;或者如果是頂級物件,則本身就是undefined,
注意,箭頭函式不能用來定義 toJSON() 方法,主要原因是箭頭函式的詞法作用域是全域作用域,在這種情況下不合適,
toJSON()方法可以與過濾函式一起使用,因此理解不同序列化流程的順序非常重要,在把物件傳給JSON.stringify()時會執行如下步驟,-
- 如果可以獲取實際的值,則呼叫
toJSON()方法獲取實際的值,否則使用默認的序列化, - 如果提供了第二個引數,則應用過濾,傳入過濾函式的值就是第 1 步回傳的值,
- 第 2 步回傳的每個值都會相應地進行序列化,
- 如果提供了第三個引數,則相應地進行縮進,理解這個順序有助于決定是創建
toJSON()方法,還是使用過濾函式,或是兩者都用,
- 如果可以獲取實際的值,則呼叫
決議選項
JSON.parse()方法也可以接收一個額外的引數,這個函式會針對每個鍵/值對都呼叫一次,- 為區別于傳給
JSON.stringify()的起過濾作用的替代函式(replacer),這個函式被稱為還原函式(reviver),- 實際上它們的格式完全一樣,即還原函式也接收兩個引數,屬性名( key )和屬性值( value ),另外也需要回傳值,
- 如果還原函式回傳
undefined,則結果中就會洗掉相應的鍵,如果回傳了其他任何值,則該值就會成為相應鍵的值插入到結果中,還原函式經常被用于把日期字串轉換為 Date 物件,
舉個栗子 :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON決議</title>
</head>
<body>
<script>
let book = {
title: "富婆通訊錄",
authors: [
"CS@zeny",
"各大富婆"
],
edition: 1,
year: 2021,
price: "100yuan",
releaseDate: new Date(2021, 01, 01) //增加了releaseDate屬性,是一個Date物件,
};
let jsonText = JSON.stringify(book); //這個物件在被序列化為JSON字串后
let bookCopy = JSON.parse(jsonText, //又被重新決議為一個物件 bookCopy
(key, value) => key == "releaseDate" ? new Date(value) : value); //這里的還原函式會查找 "releaseDate" 鍵,如果找到就會根據它的日期字串創建新的 Date 物件
alert("回傳的年份:" + bookCopy.releaseDate.getFullYear()); //得到的 bookCopy.releaseDate 屬性又變回了Date 物件,因此可以呼叫其 getFullYear()方法來獲取年份,
</script>
</body>
</html>
效果 :

附注 : getFullYear()是Date類下的方法;作用 : 回傳 4 位數年(即 2021而不是 21)
JSON 的優點
JSON 是一種輕量級資料格式,可以方便地表示復雜資料結構,這個格式使用 JavaScript 語法的一個子集表示物件、陣列、字串、數值、布林值和 null ,雖然 XML 也能勝任同樣的角色,但 JSON 更簡潔,JavaScript 支持也更好,更重要的是,所有瀏覽器都已經原生支持全域 JSON 物件,
ENDING
參考書籍 : Javascript高級程式設計:第4版/ (美)馬特·弗里斯比(Matt Frisbie)著;李松峰譯. 北京:人民郵電出版社,2020.9 第23章 JSON P704.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/395152.html
標籤:其他
上一篇:黑馬微信小程式入門
