JSON(JavaScript Object Notation)
,指JavaScript
的物件表示法,它本身是個字串,是一種資料交換格式,並非物件。通常所提的JSON
物件實際是JSON
字串解析成物件的結果,或是瀏覽器window
物件下的JSON
物件。
而且JSON
不止用於JavaScript
中,其廣泛用於資料交換。
JSON和JavaScript物件
一個JSON
檔案,或一段JSON
字串,通常是這樣的:
[{
"name": "使用者許可權管理",
"code": "99990002",
"icon": "modicon-1",
"items": [{
"name": "模組許可權",
"code": "999900020009",
"url": "",
"isBlank": false,
"items": [{
"name": "嚮導模板",
"code": "9999000200090003",
"url": "pages/accLayoutTest.html",
"isBlank": false,
"items": []
}, {
"name": "模組管理我們的",
"code": "9999000200090001",
"url": "pages/contentPageTest.html",
"isBlank": false,
"items": []
}]
}]
}, ... ]
而這樣類似的JavaScript
物件則是這樣的:
var menuData = [{
name: "使用者許可權管理",
code: "99990002",
icon: "modicon-1",
items: [{
name: "模組許可權",
code: "999900020009",
url: "",
isBlank: false,
items: [{
name: "嚮導模板",
code: "9999000200090003",
url: "pages/accLayoutTest.html",
isBlank: false,
items: []
}, {
name: "模組管理我們的",
code: "9999000200090001",
url: "pages/contentPageTest.html",
isBlank: false,
items: []
}]
}]
}, ...]
兩者非常的相似,所不同的是就是JavaScript
物件中屬性名,也就是物件的key
值是可以沒有引號的,其值為字串時,使用``
和""
包裹均可。 因此我們很多人將第一段程式碼塊裡所寫的JSON
稱為JSON物件,實際上,它並不是一個物件,只是一個單純的字串而已,但是它符合JSON
的語法規則,可以很方便地轉化為JavaScript
物件,或者方便地用於資料交換。
以下我們來了解一下JSON
。
JSON語法
-
JSON語法規則
JSON 語法是 JavaScript 物件表示語法的子集,其基本原則如下:
-
資料在鍵值對中
-
資料由逗號分隔
-
花括號儲存物件
-
方括號儲存陣列
-
-
JSON的值
-
數字(整數或浮點數)
-
字串(在雙引號中)
-
邏輯值(
true
或false
) -
陣列(在方括號中
[]
) -
物件(在花括號中
{}
) -
null
-
JSON
作為一種資料交換格式,為了保證其能被正確方便的解析,其格式有嚴格的要求,必須遵循以下規則:
-
複合型別的值只能是陣列或物件,不能是函式、正規表示式物件、日期物件。
-
簡單型別的值只有四種:字串、數值(必須以十進位制表示)、布林值和
null
(不能使用NaN
,Infinity
,-Infinity
和undefined
)。 -
字串必須使用雙引號表示,不能使用單引號。
-
物件的鍵名必須放在雙引號裡面。
-
陣列或物件最後一個成員的後面,不能有逗號。
-
數值前不能加0。
以下是合法的JSON
格式示例:
["one", "two", "three"]
{
"one": 1,
"two": 2,
"three": 3
}
{
"names": [
"張三",
"李四"
]
}
[
{ "name": "張三" },
{ "name": "李四" }
]
下面這些就是不合法的:
{
name: "張三",
`age`: 32
} // 屬性名必須使用雙引號
[32, 64, 128, 0xFFF] // 不能使用十六進位制值
{
"name": "張三",
"age": undefined
} // 不能使用undefined
{
"name": "張三",
"birthday": new Date(`Fri, 26 Aug 2011 07:13:10 GMT`),
"getName": function() {
return this.name;
}
} // 不能使用函式和日期物件
{
"name": "李四",
"age": 018
} // 數值前不能有0
以上程式碼中為了指出錯誤所在,使用了
JavaScript
的註釋法,實際JSON
中是不能有註釋的。不合法的
JSON
會在解析成JavaScript
物件時,出現錯誤。
JSON和JavaScript物件的轉化
window.JSON
JSON
作為一種資料交換格式,被寫入了ECMAScript 5,在IE8及之後的瀏覽器都提供了一個JSON
物件,用於對JSON
進行解析和序列化。
JSON.parse()
此方法接收一個JSON
字串,返回解析後的JavaScript物件,通常為Object
或Array
。
// JSON資料
var humansData = `[{"name":"zs","age":28},{"name":"ls","age":26}]`;
// 解析為JavaScript物件
var humans = JSON.parse(humansData);
// 之後就可以訪問其元素或屬性了
humans[1].name; // ls
humans[1].age; // 26
如果傳入不合法的
JSON
,則會在JSON.parse
時報錯。
為什麼我們在ajax請求中,即使請求的資料為JSON
,我們不用解析就能直接使用呢?
// test.text內容
/*
[{
"name":"zs",
"age":28
},{
"name":"ls",
"age":26
}]
*/
$.ajax({
url: `./test/test.text`,
dataType: `JSON`
}).done(function(data){
console.dir(data); // Array[2]
console.log(data[0].name); // zs
// 這裡沒有轉化為js物件就能訪問其屬性?!
});
這裡實際是因為指定了dataType
為JSON,從而進行了自動轉化,所以能直接在成功回撥中使用其屬性。如果去掉dataType
的指定,就不能直接訪問其屬性了,因為未轉化時,其本身是一個字串。第一行輸出為test.text的內容,第二行輸出undefined
。
JSON.stringify()
此方法可接收一個JavaScript
值將轉化為JSON
字串,此字串可被JSON.parse
還原。
var humans = [{
"name": "zs",
"age": 28,
"birth": new Date()
}, {
"name": "ls",
"age": 26,
"birth": new Date()
}];
// 轉化為JSON字串
JSON.stringify(humans);
// "[{"name":"zs","age":28,"birth":"2016-10-25T07:24:11.701Z"},{"name":"ls","age":26,"birth":"2016-10-25T07:24:11.701Z"}]"
前面我們講到了JSON
中並非支援所有的JavaScript
型別,因此此方法對一些JSON
不可接受的值有所處理:原始物件中,如果有一個成員的值是undefined、函式或XML物件,這個成員會被省略。如果陣列的成員是undefined、函式或XML物件,則這些值被轉成null。
我們還發現,JSON
中是不支援Date
物件的,而上述轉化為字串的結果中正確包含了birth
的值,其為一個日期格式的字串。這是因為在Date
物件上有一個名為toJSON
的方法,JSON.stringify
在序列化時,實際是呼叫了這個方法來輸出結果的。
如果一個被序列化的物件擁有 toJSON 方法,那麼該 toJSON 方法就會覆蓋該物件預設的序列化行為:不是那個物件被序列化,而是呼叫 toJSON 方法後的返回值會被序列化,例如:
var obj = {
foo: `foo`,
toJSON: function() {
return `bar`;
}
};
JSON.stringify(obj); // `"bar"`
JSON.stringify({x: obj}); // `{"x":"bar"}`
瞭解即可,詳見: MDN:JSON.stringify(){.doc-link}
我們可能經常看到的是JSON.stringify( obj , null , 4)
,這樣是什麼意思呢?
對於上例,替換最後一句,結果如下所示:
JSON.stringify(humans, null, 4);
// "[
// {
// "name": "zs",
// "age": 28,
// "birth": "2016-10-25T07:24:11.701Z"
// },
// {
// "name": "ls",
// "age": 26,
// "birth": "2016-10-25T07:24:11.701Z"
// }
// ]"
其實沒什麼變化,不過是加上了空格縮排,使得可讀性更高了。
其餘兩個引數的說明如下:
-
第二個引數可指定序列化時的操作。
-
如果該引數是一個函式,則在序列化過程中,被序列化的值的每個屬性都會經過該函式的轉換和處理;
-
如果該引數是一個陣列,則只有包含在這個陣列中的屬性名才會被序列化到最終的 JSON 字串中;
-
如果該引數為null或者未提供,則物件所有的屬性都會被序列化;
-
-
第三個引數用於指定縮排用的空白字串,用於美化輸出(pretty-print);
-
如果引數是個數字,它代表有多少的空格;上限為10。該值若小於1,則意味著沒有空格;
-
如果該引數為字串(字串的前十個字母),該字串將被作為空格;
-
如果該引數沒有提供(或者為null)將沒有空格。
-
替代方法
window.JSON
物件下雖然提供了完整的JSON
字串和JavaScript
物件的轉換方法。但是在IE8(相容模式)以及更低版本的IE下沒有提供這個物件,因此我們需要一些替代方案。
-
jQuery中提供了
parseJSON
這樣一個方法來替代JSON.parse
,它接收一個標準格式的JSON
字串,返回一個解析後的JavaScript
物件。 -
使用http://www.json.org/提供了一個json.js,這樣ie8(相容模式),ie7和ie6就可以支援JSON物件以及其
stringify()
和parse()
方法; 可以在https://github.com/douglascrockford/JSON-js上獲取到這個js,一般現在用json2.js。 -
還可以使用
eval(`(` + jsonstr + `)`)
; 來將json字串轉換成json物件,注意需要在json字元外包裹一對小括號。但最好不要使用這種方式,因為這種方式不安全,eval
會將JSON
字串作為JavaScript
語句來執行,JSON
中的風險程式碼將被執行。