使用 JSON

JavaScript 物件表示法 (JSON) 是一種基於 JavaScript 物件語法表示結構化資料的標準文字格式。它通常用於在 Web 應用程式中傳輸資料(例如,將一些資料從伺服器傳送到客戶端,以便在網頁上顯示,反之亦然)。您會經常遇到它,因此在本文中,我們為您提供了使用 JavaScript 處理 JSON 所需的所有內容,包括解析 JSON 以便您可以訪問其中的資料,以及建立 JSON。

先決條件 對 HTML 和 CSS 的基本瞭解,熟悉 JavaScript 基礎知識(參見 第一步構建塊)以及 OOJS 基礎知識(參見 物件簡介)。
目標 瞭解如何處理儲存在 JSON 中的資料,以及建立您自己的 JSON 字串。

不,真的,什麼是 JSON?

JSON 是一種基於文字的資料格式,遵循 JavaScript 物件語法,由 道格拉斯·克羅克福德 推廣。儘管它與 JavaScript 物件字面量語法非常相似,但它可以獨立於 JavaScript 使用,並且許多程式設計環境都具有讀取(解析)和生成 JSON 的能力。

JSON 存在於字串中——當您想要跨網路傳輸資料時非常有用。當您想要訪問資料時,需要將其轉換為本機 JavaScript 物件。這不是什麼大問題——JavaScript 提供了一個全域性 JSON 物件,其中包含用於在兩者之間轉換的方法。

注意:將字串轉換為本機物件稱為反序列化,而將本機物件轉換為字串以便能夠跨網路傳輸則稱為序列化

JSON 字串可以儲存在它自己的檔案中,該檔案基本上只是一個副檔名為 .jsonMIME 型別application/json 的文字檔案。

JSON 結構

如上所述,JSON 是一個字串,其格式非常類似於 JavaScript 物件字面量格式。您可以在 JSON 中包含與標準 JavaScript 物件中相同的基本資料型別——字串、數字、陣列、布林值和其他物件字面量。這允許您構建資料層次結構,如下所示

json
{
  "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 物件基礎知識 文章中看到的相同的點/括號表示法來訪問其中的資料。例如

js
superHeroes.homeTown;
superHeroes["active"];

要訪問層次結構中更深層的資料,您必須將所需的屬性名稱和陣列索引連結在一起。例如,要訪問成員列表中第二個英雄的第三個超能力,您可以執行以下操作

js
superHeroes["members"][1]["powers"][2];
  1. 首先,我們有變數名——superHeroes
  2. 在其中,我們想訪問 members 屬性,所以我們使用 ["members"]
  3. members 包含一個由物件填充的陣列。我們想訪問陣列中的第二個物件,所以我們使用 [1]
  4. 在此物件中,我們想訪問 powers 屬性,所以我們使用 ["powers"]
  5. powers 屬性中包含一個數組,其中包含所選英雄的超能力。我們想要第三個,所以我們使用 [2]

注意:我們在 JSONTest.html 示例中(參見 原始碼)的變數中提供了上面看到的 JSON。嘗試載入它,然後透過瀏覽器的 JavaScript 控制檯訪問變數中的資料。

陣列作為 JSON

上面我們提到 JSON 文字基本上看起來像字串中的 JavaScript 物件。我們還可以將陣列轉換為 JSON 或從 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.htmlstyle.css 檔案的本地副本。後者包含一些簡單的 CSS 來設定頁面的樣式,而前者包含一些非常簡單的正文 HTML,以及一個 <script> 元素,用於包含我們將在本練習中編寫的 JavaScript 程式碼

html
<header>
...
</header>

<section>
...
</section>

<script>
...
</script>

我們已在 GitHub 上提供了我們的 JSON 資料,網址為 https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json

我們將 JSON 載入到我們的指令碼中,並使用一些巧妙的 DOM 操作來顯示它,如下所示

Image of a document titled "Super hero squad" (in a fancy font) and subtitled "Hometown: Metro City // Formed: 2016". Three columns below the heading are titled "Molecule Man", "Madame Uppercut", and "Eternal Flame", respectively. Each column lists the hero's secret identity name, age, and superpowers.

頂級函式

頂級函式如下所示

js
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 物件,讓我們透過編寫上面提到的兩個函式來使用它。首先,在之前的程式碼下方新增以下函式定義

js
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() 將其附加到標題。然後,我們對段落執行非常類似的操作:建立它,設定其文字內容並將其附加到標題。唯一的區別是它的文字設定為包含物件的 homeTownformed 屬性的 模板字面量

建立英雄資訊卡

接下來,在程式碼底部新增以下函式,該函式建立並顯示超級英雄卡片

js
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 迴圈 遍歷陣列中的每個物件。對於每個物件,我們

  1. 建立幾個新元素:一個 <article>、一個 <h2>、三個 <p> 和一個 <ul>
  2. <h2> 設定為包含當前英雄的 name
  3. 使用他們的 secretIdentityage 和一行“超能力:”來填充三個段落,以介紹列表中的資訊。
  4. powers 屬性儲存在另一個名為 superPowers 的新常量中——它包含一個列出當前英雄超能力的陣列。
  5. 使用另一個 for...of 迴圈遍歷當前英雄的超能力——對於每個超能力,我們建立一個 <li> 元素,將超能力放入其中,然後使用 appendChild()listItem 放入 <ul> 元素(myList)中。
  6. 我們做的最後一件事是將 <h2><p><ul> 附加到 <article>myArticle)中,然後將 <article> 附加到 <section> 中。附加事物的順序很重要,因為這是它們在 HTML 中顯示的順序。

注意:如果您在使示例工作時遇到問題,請嘗試參考我們的 heroes-finished.html 原始碼(也可以檢視 線上執行 的程式碼)。

注意:如果您在理解我們用於訪問 JavaScript 物件的點/括號表示法時遇到困難,可以嘗試在另一個標籤頁或文字編輯器中開啟superheroes.json檔案,並在檢視 JavaScript 程式碼時參考它。您還可以參考我們的JavaScript 物件基礎文章,以獲取有關點和括號表示法的更多資訊。

呼叫頂級函式

最後,我們需要呼叫我們的頂級populate()函式

js
populate();

在物件和文字之間轉換

以上示例在訪問 JavaScript 物件方面很簡單,因為我們使用response.json()將網路響應直接轉換為 JavaScript 物件。

但有時我們沒那麼幸運——有時我們會收到原始的 JSON 字串,我們需要自己將其轉換為物件。當我們想要透過網路傳送 JavaScript 物件時,需要在傳送之前將其轉換為 JSON(字串)。幸運的是,這兩個問題在 Web 開發中非常常見,瀏覽器中提供了一個內建的JSON物件,其中包含以下兩種方法

  • parse():接受 JSON 字串作為引數,並返回相應的 JavaScript 物件。
  • stringify():接受物件作為引數,並返回等效的 JSON 字串。

您可以在我們的heroes-finished-json-parse.html示例中看到第一個方法的應用(參見原始碼)——它與我們之前構建的示例完全相同,只是

  • 我們透過呼叫響應的text()方法,以文字而不是 JSON 的形式檢索響應
  • 然後我們使用parse()將文字轉換為 JavaScript 物件。

關鍵程式碼片段如下所示

js
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 控制檯中,以檢視其執行效果

js
let myObj = { name: "Chris", age: 38 };
myObj;
let myString = JSON.stringify(myObj);
myString;

這裡我們建立了一個 JavaScript 物件,然後檢查其內容,然後使用stringify()將其轉換為 JSON 字串——將返回值儲存在一個新變數中——然後再次檢查它。

測試你的技能!

您已經閱讀完了本文,但您還記得最重要的資訊嗎?在繼續學習之前,您可以進行一些額外的測試來驗證您是否掌握了這些資訊——請參閱測試您的技能:JSON

總結

在本文中,我們為您提供了使用 JSON 進行程式設計的簡單指南,包括如何建立和解析 JSON,以及如何訪問其中包含的資料。在下一篇文章中,我們將開始學習面向物件的 JavaScript。

另請參閱