此頁面由社群從英文翻譯而來。了解更多並加入 MDN Web Docs 社群。

View in English Always switch to English

使用 JSON 資料

JavaScript Object Notation (JSON) 為將結構化資料 (structured data) 呈現為 JavaScript 物件的標準格式,常用於網站上的資料呈現、傳輸 (例如將資料從伺服器送至用戶端,以利顯示網頁)。你應該會常常遇到,因此本文將說明 JavaScript 搭配 JSON 時所應知道的觀念,包含如何在 JSON 物件中存取資料項目,並寫出你自己的 JSON。

必要條件: 基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉) 與 OOJS 基本概念 (參閱〈Introduction to objects〉)。
主旨: 了解應如何使用 JSON 格式所儲存的資料,建立自己的 JSON 物件。

說真的,到底什麼是 JSON?

JSON 是依照 JavaScript 物件語法的資料格式,經 Douglas Crockford 推廣普及。雖然 JSON 是以 JavaScript 語法為基礎,但可獨立使用,且許多程式設計環境亦可讀取 (剖析) 並產生 JSON。

JSON 可能是物件或字串。當你想從 JSON 中讀取資料時,JSON 可作為物件;當要跨網路傳送 JSON 時,就會是字串。這不是什麼大問題 — JavaScript 提供全域 JSON 物件,其內的函式可進行切換。

JSON 物件可儲存於其自有的檔案中,基本上就是副檔名為 .json 的文字檔案,以及 application/jsonMIME type

JSON 的架構

我們剛提到「JSON 物件基本上就是 JavaScript 物件」,而這敘述在大多數情況下都對。如同標準的 JavaScript 物件,你當然可在 JSON 之內加入相同的基本資料類型,如字串、數字、陣列、布林值,以及其他物件,接著同樣能再建構出資料繼承,如:

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 屬性中有 1 個陣列具備所選超級英雄的能力。我們要選第三種能力,所以用 [2]

備註: 我們在 JSONText.html 範例 (參閱原始碼) 的變數中,示範上述可用的 JSON。你可在自己瀏覽器的 JavaScript 主控台載入此程式碼,並存取變數中的資料。

陣列作為 JSON

我們在上面提過「 JSON 物件基本上就是 JavaScript 物件,而這敘述在大多數情況下都對」。其中「在大多數情況下都對」的理由,就是因為陣列也可以是有效的 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 也就不容易出錯)。你可透過如 JSONLint 的應用程式檢驗 JSON。
  • 不限於陣列或物件,只要是符合標準 JSON 物件形式的任何資料,都可以夾帶進 JSON 檔案中。因此,單一字串或數字也可能是有效的 JSON 物件,但不一定有用就是了...

主動學習:完成 JSON 範例

現在就試著在網站上,透過某些 JSON 資料完成範例吧。

入門

在開始之前,先複製我們的 heroes.htmlstyle.css 到你的本端硬碟中。後者包含某些簡易的 CSS 可塑造網頁風格;前者則提供極簡單主體 HTML:

html
<header></header>

<section></section>

加上 <script> 元素,才能納入稍後會在此習題中寫出來的 JavaScript 程式碼。目前只有 2 行程式碼,用以取得 <header><section> 元素的參考,並將之儲存於變數之中:

js
var header = document.querySelector("header");
var section = document.querySelector("section");

你可到 GitHub 上找到此 JSON 資料:https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json

接著載入到頁面之中,並使用某些有趣的 DOM 操控 (DOM manipulation) 來顯示,如下:

載入我們的 JSON

若要將 JSON 載入至頁面,就要透過 XMLHttpRequest API (通常稱為 XHR)。此是極好用的 JavaScript 物件,可讓網路請求透過 JavaScript (例如圖片、文字、JSON,甚至 HTML 片段) 來檢索伺幅器的資源,這也代表我們不需載入整個頁面,就能更新小部分的內容。如此可讓網頁反應速度更快;聽起來很棒吧?但可惜本文無法再深入講解更多細節。

  1. 一開始,我們先針對要在變數中檢索的 JSON 檔案,將其網址儲存起來。把下列程式碼加到你 JavaScript 程式碼的最下方:

    js
    var requestURL =
      "https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
    
  2. 為了建立請求,我們必須透過 new 關鍵字,先從 XMLHttpRequest 建構子建立新的請求物件實例。把下列加到最後一行:

    js
    var request = new XMLHttpRequest();
    
  3. 現在用 open() 函式開啟新的請求。加入下列程式碼:

    js
    request.open("GET", requestURL);
    

    這樣就顧到至少 2 個參數。當然也有其他參數可選擇。但這個簡易範例只需要 2 個強制參數:

    • 在設立網路請求時,應使用 HTTP 函式。因為這裡只要檢索簡單的資料,所以用 GET 就可以。
    • URL 提供請求目的地 — 這也就是我們剛剛儲存的 JSON 檔案網址。
  4. 接著加入下面 2 行程式碼。我們為 JSON 設定了 responseType,告知伺服器應回傳 JSON 物件,再以 send() 函式傳送請求:

    js
    request.responseType = "json";
    request.send();
    
  5. 最後就是等待由伺服器所回傳的反應,再接著處理。把下列程式碼加入現有程式碼的最下方:

    js
    request.onload = function () {
      var superHeroes = request.response;
      populateHeader(superHeroes);
      showHeroes(superHeroes);
    };
    

在這裡,我們將所獲得的響應 (可到 response 屬性中找到) 儲存到 superHeroes 變數之中。此變數現在會納入我們的 JSON。接著再把此 JSON 檔案送到 2 個函式呼叫。第一個函式呼叫會將正確資料填入 <header>;第二個函式呼叫則會為團隊中的各個英文建立資訊卡,再插入至 <section> 內。

當於請求物件上觸發載入事件時,會執行一個事件處理器。我們就將程式碼包裹至此處理器之中 (參閱 onload) — 只要成功回傳響應,就會觸發載入事件。之所以這樣做,是為了確保當我們要以 request.response 進行某件事時,此 request.response 絕對可用。

產生標頭

現在檢索過了 JSON 資料,接著就寫出上面參照過的 2 個函式來利用 JSON 資料吧。首先將下列函式定義加到先前的程式碼中:

js
function populateHeader(jsonObj) {
  var myH1 = document.createElement("h1");
  myH1.textContent = jsonObj["squadName"];
  header.appendChild(myH1);

  var myPara = document.createElement("p");
  myPara.textContent =
    "Hometown: " + jsonObj["homeTown"] + " // Formed: " + jsonObj["formed"];
  header.appendChild(myPara);
}

我們已經將參數命名為 jsonObj,所以在這個函式之內就要用 jsonObj 呼叫此參數。這裡先以 createElement() 建立 1 組 <h1> 元素、將其 textContent 指定為 JSON 的 squadName 屬性、透過 appendChild() 將之附加到標頭。接著 <p> 元素依樣畫葫蘆一遍:建立、設定其文字內容、附加到標頭。唯一不同之處,就是將該文字設定為 1 組串接字串 (Concatenated string),其內包含 JSON 的 homeTownformed 屬性。

建立超級英雄的資訊卡片

現在將下列函式加到程式碼底端,用以建立並顯示超級英雄的卡片:

js
function showHeroes(jsonObj) {
  var heroes = jsonObj["members"];

  for (i = 0; i < heroes.length; i++) {
    var myArticle = document.createElement("article");
    var myH2 = document.createElement("h2");
    var myPara1 = document.createElement("p");
    var myPara2 = document.createElement("p");
    var myPara3 = document.createElement("p");
    var myList = document.createElement("ul");

    myH2.textContent = heroes[i].name;
    myPara1.textContent = "Secret identity: " + heroes[i].secretIdentity;
    myPara2.textContent = "Age: " + heroes[i].age;
    myPara3.textContent = "Superpowers:";

    var superPowers = heroes[i].powers;
    for (j = 0; j < superPowers.length; j++) {
      var listItem = document.createElement("li");
      listItem.textContent = superPowers[j];
      myList.appendChild(listItem);
    }

    myArticle.appendChild(myH2);
    myArticle.appendChild(myPara1);
    myArticle.appendChild(myPara2);
    myArticle.appendChild(myPara3);
    myArticle.appendChild(myList);

    section.appendChild(myArticle);
  }
}

我們先把 JSON 的 members 屬性儲存到新的變數中。此陣列所具備的多個物件,均包含了各個超級英雄的資訊。

接著我們以 for 迴圈循環陣列中的各個物件。針對每個物件都會:

  1. 建立數個新的元素:1 組 <article>、1 組 <h2>、3 組 <p>、1 組 <ul>
  2. <h2> 納入目前超級英雄的 name
  3. 接著 3 個段落分別是英雄的 secretIdentityageSuperpowers,在列表中帶出相關資訊。
  4. 另以新變數 superPowers 儲存 powers 屬性 — 其中包含 1 組陣列以列出目前英雄的超能力。
  5. 再用另一個 for 迴圈逐一巡過目前英雄的超能力。針對每一項超能力,我們再建立 1 組 <li> 元素,把超能力放進該元素之中,再透過 appendChild()listItem 放入 <ul> 元素之內 (myList)。
  6. 最後就是在 <article> (myArticle) 之內附加 <h2><p><ul>;再把 <article> 附加於 <section> 之內。這附加的順序極為重要,因為這也會是 HTML 中的顯示順序。

備註: 如果你無法讓此範例運作,可參閱我們的 heroes-finished.html 原始碼 (亦可看到實際執行情況。)

備註: 如果你無法用我們說過的點記法 (dot-)\括弧記法 (bracket notation) 來存取 JSON,則可用新分頁或自己的文字編輯器開啟 superheroes.json 檔案並參考之。你也可再回去看看 JavaScript 物件基礎概念 ,再次了解點\括弧記法。

物件與文字交互轉換

上述是存取 JSON 的簡易範例,因為我們設定要回傳響應的 XHR 已經是 JSON 格式。透過:

js
request.responseType = "json";

但有時候沒這麼好運。我們有時會接收到文字字串格式的 JSON 資料,且必須將之轉換為物件。且當我們要以某種訊息傳送 JSON 資料時,也必須將之轉換為字串才能正確運作。還好,這 2 種問題在 Web 開發過程中甚為常見。內建的 JSON 物件很早就新增到瀏覽器之中,且包含下列 2 種函式:

  • parse():接收文字字串形式的 JSON 物件作為參數,並回傳對應的物件。
  • stringify():接收 JSON 物件作為參數,並回傳對等的文字字串形式。

你可到 heroes-finished-json-parse.html 範例 (參閱原始碼) 中看到第一個函式的運作情形。這其實跟我們先前範例所進行的事情一模一樣,不同之處在於我們設定 XHR 要回傳 JSON 為文字,接著再使用 parse() 轉換為實際的 JSON 物件。關鍵程式碼片段如下:

js
request.open("GET", requestURL);
request.responseType = "text"; // now we're getting a string!
request.send();

request.onload = function () {
  var superHeroesText = request.response; // get the string from the response
  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
  populateHeader(superHeroes);
  showHeroes(superHeroes);
};

你可能會猜 stringify() 就是反過來運作了吧?可在瀏覽器的 JavaScript 主控台上輸入下列程式碼,看看其運作方式:

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

這樣就建立了 JSON 物件了。接著檢查內容物之後,就可透過 stringify() 將之轉換為字串。將回傳值儲存到新變數之中,再檢查一次即可。

摘要

我們透過本文簡單介紹了該如何在程式中使用 JSON、該如何建立\剖析 JSON、該如何存取其內的資料。接著就要說明物件導向 JavaScript(OOJS)。

參見

close