使用 JSON
JavaScript 物件表示法 (JSON) 是一種基於 JavaScript 物件語法表示結構化資料的標準文字格式。它通常用於在 Web 應用程式中傳輸資料(例如,將一些資料從伺服器傳送到客戶端,以便在網頁上顯示,反之亦然)。您會經常遇到它,因此在本文中,我們為您提供了使用 JavaScript 處理 JSON 所需的所有內容,包括解析 JSON 以便您可以訪問其中的資料,以及建立 JSON。
不,真的,什麼是 JSON?
JSON 是一種基於文字的資料格式,遵循 JavaScript 物件語法,由 道格拉斯·克羅克福德 推廣。儘管它與 JavaScript 物件字面量語法非常相似,但它可以獨立於 JavaScript 使用,並且許多程式設計環境都具有讀取(解析)和生成 JSON 的能力。
JSON 存在於字串中——當您想要跨網路傳輸資料時非常有用。當您想要訪問資料時,需要將其轉換為本機 JavaScript 物件。這不是什麼大問題——JavaScript 提供了一個全域性 JSON 物件,其中包含用於在兩者之間轉換的方法。
注意:將字串轉換為本機物件稱為反序列化,而將本機物件轉換為字串以便能夠跨網路傳輸則稱為序列化。
JSON 字串可以儲存在它自己的檔案中,該檔案基本上只是一個副檔名為 .json 且 MIME 型別 為 application/json 的文字檔案。
JSON 結構
如上所述,JSON 是一個字串,其格式非常類似於 JavaScript 物件字面量格式。您可以在 JSON 中包含與標準 JavaScript 物件中相同的基本資料型別——字串、數字、陣列、布林值和其他物件字面量。這允許您構建資料層次結構,如下所示
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": [
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
}
]
}
例如,如果我們將此字串載入到 JavaScript 程式中並將其解析到名為 superHeroes 的變數中,那麼我們就可以使用我們在 JavaScript 物件基礎知識 文章中看到的相同的點/括號表示法來訪問其中的資料。例如
superHeroes.homeTown;
superHeroes["active"];
要訪問層次結構中更深層的資料,您必須將所需的屬性名稱和陣列索引連結在一起。例如,要訪問成員列表中第二個英雄的第三個超能力,您可以執行以下操作
superHeroes["members"][1]["powers"][2];
- 首先,我們有變數名——
superHeroes。 - 在其中,我們想訪問
members屬性,所以我們使用["members"]。 members包含一個由物件填充的陣列。我們想訪問陣列中的第二個物件,所以我們使用[1]。- 在此物件中,我們想訪問
powers屬性,所以我們使用["powers"]。 powers屬性中包含一個數組,其中包含所選英雄的超能力。我們想要第三個,所以我們使用[2]。
注意:我們在 JSONTest.html 示例中(參見 原始碼)的變數中提供了上面看到的 JSON。嘗試載入它,然後透過瀏覽器的 JavaScript 控制檯訪問變數中的資料。
陣列作為 JSON
上面我們提到 JSON 文字基本上看起來像字串中的 JavaScript 物件。我們還可以將陣列轉換為 JSON 或從 JSON 轉換。例如,下面也是有效的 JSON
[
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
}
]
以上是完全有效的 JSON。您只需要從陣列索引開始訪問陣列項(在其解析版本中),例如 [0]["powers"][0]。
其他說明
- JSON 純粹是一個具有指定資料格式的字串——它只包含屬性,不包含方法。
- JSON 要求在字串和屬性名稱周圍使用雙引號。除了圍繞整個 JSON 字串之外,單引號無效。
- 即使是一個錯位的逗號或冒號也會導致 JSON 檔案出錯,無法工作。您應該小心驗證您嘗試使用的任何資料(儘管計算機生成的 JSON 出現錯誤的可能性較小,只要生成器程式工作正常)。您可以使用 JSONLint 等應用程式驗證 JSON。
- JSON 實際上可以採用任何對包含在 JSON 中有效的任何資料型別,而不僅僅是陣列或物件。因此,例如,單個字串或數字將是有效的 JSON。
- 與 JavaScript 程式碼中物件屬性可以不帶引號不同,在 JSON 中,只有帶引號的字串可以用作屬性。
主動學習:完成 JSON 示例
因此,讓我們透過一個示例來演示如何在網站上使用一些 JSON 格式的資料。
入門
首先,建立我們 heroes.html 和 style.css 檔案的本地副本。後者包含一些簡單的 CSS 來設定頁面的樣式,而前者包含一些非常簡單的正文 HTML,以及一個 <script> 元素,用於包含我們將在本練習中編寫的 JavaScript 程式碼
<header>
...
</header>
<section>
...
</section>
<script>
...
</script>
我們已在 GitHub 上提供了我們的 JSON 資料,網址為 https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json。
我們將 JSON 載入到我們的指令碼中,並使用一些巧妙的 DOM 操作來顯示它,如下所示
頂級函式
頂級函式如下所示
async function populate() {
const requestURL =
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
const request = new Request(requestURL);
const response = await fetch(request);
const superHeroes = await response.json();
populateHeader(superHeroes);
populateHeroes(superHeroes);
}
為了獲取 JSON,我們使用了一個名為 Fetch 的 API。此 API 允許我們透過 JavaScript 發出網路請求以從伺服器檢索資源(例如影像、文字、JSON,甚至 HTML 片段),這意味著我們可以在不重新載入整個頁面的情況下更新少量內容。
在我們的函式中,前四行使用 Fetch API 從伺服器獲取 JSON
- 我們宣告
requestURL變數來儲存 GitHub URL - 我們使用 URL 初始化一個新的
Request物件。 - 我們使用
fetch()函式發出網路請求,這將返回一個Response物件 - 我們使用
Response物件的json()函式以 JSON 格式檢索響應。
注意:fetch() API 是非同步的。我們將在 下一個模組 中詳細瞭解非同步函式,但現在,我們只說我們需要在使用 fetch API 的函式名稱之前新增關鍵字 async,並在對任何非同步函式的呼叫之前新增關鍵字 await。
在所有這些之後,superHeroes 變數將包含基於 JSON 的 JavaScript 物件。然後,我們將該物件傳遞給兩個函式呼叫——第一個函式使用正確的資料填充 <header>,而第二個函式為團隊中的每個英雄建立一個資訊卡,並將其插入 <section> 中。
填充標題
現在我們已經檢索了 JSON 資料並將其轉換為 JavaScript 物件,讓我們透過編寫上面提到的兩個函式來使用它。首先,在之前的程式碼下方新增以下函式定義
function populateHeader(obj) {
const header = document.querySelector("header");
const myH1 = document.createElement("h1");
myH1.textContent = obj.squadName;
header.appendChild(myH1);
const myPara = document.createElement("p");
myPara.textContent = `Hometown: ${obj.homeTown} // Formed: ${obj.formed}`;
header.appendChild(myPara);
}
在這裡,我們首先使用 createElement() 建立一個 h1 元素,將其 textContent 設定為等於物件的 squadName 屬性,然後使用 appendChild() 將其附加到標題。然後,我們對段落執行非常類似的操作:建立它,設定其文字內容並將其附加到標題。唯一的區別是它的文字設定為包含物件的 homeTown 和 formed 屬性的 模板字面量。
建立英雄資訊卡
接下來,在程式碼底部新增以下函式,該函式建立並顯示超級英雄卡片
function populateHeroes(obj) {
const section = document.querySelector("section");
const heroes = obj.members;
for (const hero of heroes) {
const myArticle = document.createElement("article");
const myH2 = document.createElement("h2");
const myPara1 = document.createElement("p");
const myPara2 = document.createElement("p");
const myPara3 = document.createElement("p");
const myList = document.createElement("ul");
myH2.textContent = hero.name;
myPara1.textContent = `Secret identity: ${hero.secretIdentity}`;
myPara2.textContent = `Age: ${hero.age}`;
myPara3.textContent = "Superpowers:";
const superPowers = hero.powers;
for (const power of superPowers) {
const listItem = document.createElement("li");
listItem.textContent = power;
myList.appendChild(listItem);
}
myArticle.appendChild(myH2);
myArticle.appendChild(myPara1);
myArticle.appendChild(myPara2);
myArticle.appendChild(myPara3);
myArticle.appendChild(myList);
section.appendChild(myArticle);
}
}
首先,我們將 JavaScript 物件的 members 屬性儲存在一個新變數中。此陣列包含多個包含每個英雄資訊的 物件。
接下來,我們使用 for...of 迴圈 遍歷陣列中的每個物件。對於每個物件,我們
- 建立幾個新元素:一個
<article>、一個<h2>、三個<p>和一個<ul>。 - 將
<h2>設定為包含當前英雄的name。 - 使用他們的
secretIdentity、age和一行“超能力:”來填充三個段落,以介紹列表中的資訊。 - 將
powers屬性儲存在另一個名為superPowers的新常量中——它包含一個列出當前英雄超能力的陣列。 - 使用另一個
for...of迴圈遍歷當前英雄的超能力——對於每個超能力,我們建立一個<li>元素,將超能力放入其中,然後使用appendChild()將listItem放入<ul>元素(myList)中。 - 我們做的最後一件事是將
<h2>、<p>和<ul>附加到<article>(myArticle)中,然後將<article>附加到<section>中。附加事物的順序很重要,因為這是它們在 HTML 中顯示的順序。
注意:如果您在使示例工作時遇到問題,請嘗試參考我們的 heroes-finished.html 原始碼(也可以檢視 線上執行 的程式碼)。
注意:如果您在理解我們用於訪問 JavaScript 物件的點/括號表示法時遇到困難,可以嘗試在另一個標籤頁或文字編輯器中開啟superheroes.json檔案,並在檢視 JavaScript 程式碼時參考它。您還可以參考我們的JavaScript 物件基礎文章,以獲取有關點和括號表示法的更多資訊。
呼叫頂級函式
最後,我們需要呼叫我們的頂級populate()函式
populate();
在物件和文字之間轉換
以上示例在訪問 JavaScript 物件方面很簡單,因為我們使用response.json()將網路響應直接轉換為 JavaScript 物件。
但有時我們沒那麼幸運——有時我們會收到原始的 JSON 字串,我們需要自己將其轉換為物件。當我們想要透過網路傳送 JavaScript 物件時,需要在傳送之前將其轉換為 JSON(字串)。幸運的是,這兩個問題在 Web 開發中非常常見,瀏覽器中提供了一個內建的JSON物件,其中包含以下兩種方法
parse():接受 JSON 字串作為引數,並返回相應的 JavaScript 物件。stringify():接受物件作為引數,並返回等效的 JSON 字串。
您可以在我們的heroes-finished-json-parse.html示例中看到第一個方法的應用(參見原始碼)——它與我們之前構建的示例完全相同,只是
- 我們透過呼叫響應的
text()方法,以文字而不是 JSON 的形式檢索響應 - 然後我們使用
parse()將文字轉換為 JavaScript 物件。
關鍵程式碼片段如下所示
async function populate() {
const requestURL =
"https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
const request = new Request(requestURL);
const response = await fetch(request);
const superHeroesText = await response.text();
const superHeroes = JSON.parse(superHeroesText);
populateHeader(superHeroes);
populateHeroes(superHeroes);
}
正如您可能猜到的,stringify()的工作方式相反。嘗試逐一將以下幾行程式碼輸入到瀏覽器的 JavaScript 控制檯中,以檢視其執行效果
let myObj = { name: "Chris", age: 38 };
myObj;
let myString = JSON.stringify(myObj);
myString;
這裡我們建立了一個 JavaScript 物件,然後檢查其內容,然後使用stringify()將其轉換為 JSON 字串——將返回值儲存在一個新變數中——然後再次檢查它。
測試你的技能!
您已經閱讀完了本文,但您還記得最重要的資訊嗎?在繼續學習之前,您可以進行一些額外的測試來驗證您是否掌握了這些資訊——請參閱測試您的技能:JSON。
總結
在本文中,我們為您提供了使用 JSON 進行程式設計的簡單指南,包括如何建立和解析 JSON,以及如何訪問其中包含的資料。在下一篇文章中,我們將開始學習面向物件的 JavaScript。