快速了解JavaScript的JSON

JavaScript與JSON轉(zhuǎn)換.png

JSON(JavaScript Object Notation)是一種通用的、輕量級的數(shù)據(jù)交換格式,而不是編程語言。由于 XML 過于冗余和啰嗦, 因此,使用 JSON 代替 XML 進(jìn)行網(wǎng)絡(luò)傳輸。

一個 JSON 對象可以被儲存在它自己的文件中,這基本上就是一個文本文件,擴(kuò)展名為 .json。

JSON語法

基本上 JSON 對象就是基于 JavaScript 對象,因此,可以把 JavaScript 對象寫入 JSON 數(shù)據(jù),JSON 可以將JavaScript對象分為三類:

  • 簡單值:字符串、數(shù)值、布爾值和 null。undefined 除外。
  • 對象:復(fù)雜的數(shù)據(jù)類型,對象表示有序鍵/值對。
  • 數(shù)組:復(fù)雜的數(shù)據(jù)類型,數(shù)組表示帶有索引的有序列表,可以通過索引訪問數(shù)組中的值。

而在JSON中,使用如下語法規(guī)則:

  • 數(shù)據(jù)在鍵/值對中,且由逗號分隔。
  • 花括號保存對象,方括號保存數(shù)組。
{
    "code": 1,
    "status": true,
    "msg": "Http Request Success",
    "data": [
        {
            “id”: 2011101010,
            "name": "小趙",
            "age": 29,
            "sex": "男",
            "birthday": “1992-04-09”,
            "address": [
                "北京市通州區(qū)萬達(dá)廣場",
                "天津市",
                "河北省邯鄲市"
            ]
        },
        {
            “id”: 2011101011,
            "name": "小錢",
            "age": 27,
            "sex": "男",
            "birthday": “1994-05-01”,
            "address": [
                "北京市通州區(qū)萬達(dá)廣場",
                "天津市",
                "河北省邯鄲市"
            ]
        },
        {
            “id”: 2011101013,
            "name": "小玲",
            "age": 28,
            "sex": "女",
            "birthday": “1993-09-26”,
            "address": [
                "北京市通州區(qū)萬達(dá)廣場",
                "天津市",
                "河北省邯鄲市"
            ]
        }
    ]
}

<small>注意:JSON 簡單值中的字符串必須使用雙引號標(biāo)記,因為使用單引號會導(dǎo)致語法錯誤。</small>

序列化與解析

ECMAScipt 5 添加了用于JSON解析與序列化的 JSON 對象,該對象只包含兩個方法:

  • JSON.stringify():用于將JavaScript簡單值、對象或數(shù)組序列化為JSON字符串。
  • JSON.parse():用于將JSON格式的字符串解析為原生JavaScript值。

下面詳細(xì)介紹這兩種方法。

序列化

JSON.stringify() 方法將一個JavaScript簡單值、對象或數(shù)組轉(zhuǎn)換為JSON字符串。如果指定一個 replacer 函數(shù),則可以選擇性地替換掉,或者指定的 replacer 的數(shù)組,則可選擇性地僅包含數(shù)組指定的屬性。

stringify(value, replacer, space): string;
  • value:將要序列化成一個 JSON 字符串的值。
  • replacer:可選參數(shù),用于轉(zhuǎn)換結(jié)果的函數(shù)或數(shù)組。
  • space:可選參數(shù),控制結(jié)果中,每個屬性的間距,用于美化輸出。
let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
};
let json = JSON.stringify(student);

使用 JSON.stringify() 在默認(rèn)情況下會輸出不包含空格或縮進(jìn)的 JSON 字符串。如下是輸出的 JSON 字符串結(jié)果:

{"id":2011101011,"name":"小錢","age":27,"birthday":"1994-05-31T16:00:00.000Z","address":["北京市通州區(qū)萬達(dá)廣場","天津市","河北省邯鄲市"]}

而在序列化時,會有意地將所有函數(shù)和原型對象在結(jié)果中省略。

<small>注意:值為 undefined 的任何屬性都會被省略。</small>

replacer

如果 replacer 是一個函數(shù),則在序列化過程中,被序列化的值的每個屬性都會經(jīng)過該函數(shù)的轉(zhuǎn)換和處理;如果該參數(shù)是一個數(shù)組,則只有包含在這個數(shù)組中的屬性名才會被序列化到最終的 JSON 字符串中;如果該參數(shù)為 null 或者未提供,則對象所有的屬性都會被序列化。

JSON.stringify() 方法的 replacer 參數(shù)用于轉(zhuǎn)換結(jié)果。

如果 replacer 是一個數(shù)組,那 JSON.stringify() 返回的結(jié)果只會包含數(shù)組中列出的對象屬性。如下所示:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
};
let json = JSON.stringify(student, ["name", "address"]);

上面的例子,輸出的結(jié)果會根據(jù)第二個參數(shù)傳入的數(shù)組 ["name", "address"] 來獲取對應(yīng) nameaddress 屬性及它們的值進(jìn)行序列化:

{"name":"小錢","address":["北京市通州區(qū)","浙江省杭州市","河北省邯鄲市"]}

如果 replacer 是一個函數(shù),它將有鍵 key 和值 value 兩個參數(shù),且根據(jù)函數(shù)進(jìn)行相應(yīng)的序列化操作,且函數(shù)返回值應(yīng)當(dāng)是JSON中key對應(yīng)的value值。 key 始終是字符串,只在值不屬于某個key時,才會是空字符串。如下所示:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
};
let json = JSON.stringify(student, (key, value) => {
    console.log(typeof value);
    if (key == "address") {
        return value.join(",");
    }
    if (key == "birthday") {
        return undefined;
    }
    return value;    // 一定要提供該默認(rèn)返回值,以返回其它屬性傳入的值。
});

最終得到的JSON 字符串是這樣的:

{"id":2011101011,"name":"小錢","age":27,"address":"北京市通州區(qū),浙江省杭州市,河北省邯鄲市"}

注意:使用 replacer 序列化得到的JSON在使用parse進(jìn)行解析,就只會得到JSON中的屬性。

space

space 參數(shù)用于控制縮進(jìn)和空格。當(dāng)該參數(shù)為數(shù)值時,表示每一級縮進(jìn)的空格數(shù)。如下所示:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
}
let json = JSON.stringify(student, null, 4);

輸出的 JSON 格式如下所示:

{
    "id": 2011101011,
    "name": "小錢",
    "age": 27,
    "birthday": "1994-05-31T16:00:00.000Z",
    "address": [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
}

<small>注意:除了縮進(jìn),JSON.stringify() 方法還很方便地插入了換行符。最大縮進(jìn)值為 10,大于 10 的值自動設(shè)置為 10;最小縮進(jìn)值為 1,小于 1 的值意味著沒有縮進(jìn)字符。</small>

當(dāng)該參數(shù)為字符串時,將指定該字符串為空格;如果沒有提供,或者值為 null,將沒有空格。若兩個連字符:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
}
let json = JSON.stringify(student, null, "--");

輸出的 JSON 格式如下:

{
--"id": 2011101011,
--"name": "小錢",
--"age": 27,
--"birthday": "1994-05-31T16:00:00.000Z",
--"address": [
----"北京市通州區(qū)",
----"浙江省杭州市",
----"河北省邯鄲市"
--]
}

也可以使用空格 " " 、制表符 '\t'Tab來設(shè)置縮進(jìn)字符。如下所示:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
}
let json = JSON.stringify(student, null, '\t');

輸出的 JSON 格式如下:

{
    "id": 2011101011,
    "name": "小錢",
    "age": 27,
    "birthday": "1994-05-31T16:00:00.000Z",
    "address": [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ]
}

<small>注意:使用字符串時同樣有 10 個字符的長度限制。如果字符串長度超過 10,則會在第 10 個字符處截斷。</small>

toJSON()

如果對象之中定義了 toJSON() 方法,JSON.stringify() 就會調(diào)用該對象的 toJSON() 方法,覆蓋默認(rèn)序列化行為。如下所示:

let student = {
    id: 2011101011,
    name: "小錢",
    age: 27,
    sex: undefined,
    birthday: new Date(1994, 5, 1),
    address: [
        "北京市通州區(qū)",
        "浙江省杭州市",
        "河北省邯鄲市"
    ],
    toJSON: function () {
        return {
            name: this.name,
            age: this.age
        };
    }
}
let json = JSON.stringify(student, null, " ");

輸出的 JSON 格式如下:

{
 "name": "小錢",
 "age": 27
}

toJSON() 方法可以返回任意序列化值,都可以起到相應(yīng)的作用。

<small>注意:箭頭函數(shù)不能用來定義toJSON()方法。主要原因是箭頭函數(shù)的詞法作用域是全局作用域,在這種情況下不適合。</small>

toJSON() 方法可以與 replacer 一起使用,因此,序列化流程的順序非常重要。在把對象傳給 JSON.stringify() 時會執(zhí)行如下步驟。

  1. 如果定義了 toJSON()方法且能獲取到實際值,則調(diào)用toJSON()方法,否則使用默認(rèn)的序列化。
  2. 如果定義了JSON.stringify()方法的replacer函數(shù),則使用replacer函數(shù)。傳入的值就是第 1 步返回的值。
  3. 第 2 步返回的每個值都會相應(yīng)地進(jìn)行序列化。
  4. 如果提供了space 參數(shù),則相應(yīng)地進(jìn)行縮進(jìn)。

理解這個順序有助于決定是創(chuàng)建 toJSON() 方法,還是使用replacer函數(shù),抑或是兩者都用。

解析

JSON.parse() 方法用來解析 JSON 字符串,構(gòu)造由字符串描述的 JavaScript 值或?qū)ο?。提供可選的 reviver 函數(shù)用以在返回之前對所得到的對象執(zhí)行變換(操作)。

parse(text, reviver): any;
  • text:要被解析成 JavaScript 值的字符串。
  • reviver:可選參數(shù),用于修改解析生成的原始值。
let json = '{' +
    '"id":2011101011,' +
    '"name":"小錢",' +
    '"age":27,' +
    '"birthday":"1994-05-31T16:00:00.000Z",' +
    '"address":[' +
        '"北京市通州區(qū)",' +
        '"浙江省杭州市",' +
        '"河北省邯鄲市"' +
    ']' +
'}'
let student = JSON.parse(json);

輸出的對象為:

{
  id: 2011101011,
  name: '小錢',
  age: 27,
  birthday: '1994-05-31T16:00:00.000Z',
  address: [ '北京市通州區(qū)', '浙江省杭州市', '河北省邯鄲市' ]
}

<small>注意:如果給 JSON.parse() 傳入的 JSON 字符串無效,則會拋出異常。</small>

let book = {
    title: "Professional JavaScript",
    authors: [
        "Nicholas C. Zakas",
        "Matt Frisbie"
    ],
    edition: 4,
    year: 2017,
    releaseDate: new Date(2017, 11, 1)
};
let jsonText = JSON.stringify(book);
let bookCopy = JSON.parse(jsonText,
(key, value) => key == "releaseDate" ? new Date(value) : value);
alert(bookCopy.releaseDate.getFullYear());

reviver

reviver 參數(shù)是一個還原函數(shù),如果指定了還原函數(shù),將解析出的 JavaScript 值經(jīng)過一次轉(zhuǎn)換后返回最終值。該函數(shù)的調(diào)用時機在 parse 函數(shù)返回之前,并接收 keyvalue 兩個參數(shù)。如果返回 undefined,結(jié)果會刪除與 undefined 相對應(yīng)的 key;而返回其它值,則該值會成為相應(yīng)鍵的值并插入到返回結(jié)果中。

let json = '{' +
    '"id":2011101011,' +
    '"name":"小錢",' +
    '"age":27,' +
    '"birthday":"1994-05-31T16:00:00.000Z",' +
    '"address":[' +
        '"北京市通州區(qū)",' +
        '"浙江省杭州市",' +
        '"河北省邯鄲市"' +
    ']' +
'}'
let student = JSON.parse(json, (key, value) => {
    if (key == "birthday") {
        return new Date(value);
    }
    return value;
});

在上面的代碼中,JSON.parse() 方法中,定義了一個還原函數(shù),獲取 birthday 鍵并重新創(chuàng)建新的 Date 對象。最后, student.birthday 屬性變成了 Date 對象,可以調(diào)用有關(guān) Date 類的方法了。

總結(jié)

通過上面的簡單介紹,JSON 這種數(shù)據(jù)結(jié)構(gòu)可以很方便地表示復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如 JavaScript 中的數(shù)字、字符串、布爾值、數(shù)組、對象和 null 都可以用 JSON 格式表示。且比 XML 更加輕量級。而且,現(xiàn)代瀏覽器都已經(jīng)原生支持全局 JSON 對象,并且使用 JSON.stringify()JSON.parse() 方法實現(xiàn)了JavaScript與JSON之間相互轉(zhuǎn)換。

更多內(nèi)容請關(guān)注公眾號「海人為記

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容