--- title: 使用 JSON 資料 slug: Learn/JavaScript/Objects/JSON tags: - JSON translation_of: Learn/JavaScript/Objects/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 物件。 |
{{glossary("JSON")}} 是依照 JavaScript 物件語法的資料格式,經 Douglas Crockford 推廣普及。雖然 JSON 是以 JavaScript 語法為基礎,但可獨立使用,且許多程式設計環境亦可讀取 (剖析) 並產生 JSON。
JSON 可能是物件或字串。當你想從 JSON中讀取資料時,JSON可作為物件;當要跨網路傳送 JSON 時,就會是字串。這不是什麼大問題 — JavaScript 提供全域 JSON 物件,其內的函式可進行切換。
JSON 物件可儲存於其自有的檔案中,基本上就是副檔名為 .json 的文字檔案,以及 application/json 的 {{glossary("MIME type")}}。
我們剛提到「JSON 物件基本上就是 JavaScript 物件」,而這敘述在大多數情況下都對。如同標準的 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 物件基本概念〉一文中提過的,接著能以相同的 存取其內部的資料,如下:
superHeroes.hometown superHeroes["active"]
若要順著繼承往下存取資料,只要將必要的屬性名稱與陣列索引「鍊」在一起即可。舉例來說,如果要存取成員列表中的第二位英雄的第三項超能力,你必須:
superHeroes["members"][1]["powers"][2]
superHeroes。members 屬性,所以用 ["members"]。members 包含由物件產生陣列。我們要存取陣列中的第二個物件,所以用 [1]。powers 屬性,所以用 ["powers"]。powers 屬性中有 1 個陣列具備所選超級英雄的能力。我們要選第三種能力,所以用 [2]。注意:我們在 JSONText.html 範例 (參閱原始碼) 的變數中,示範上述可用的 JSON。你可在自己瀏覽器的 JavaScript 主控台載入此程式碼,並存取變數中的資料。
我們在上面提過「 JSON 物件基本上就是 JavaScript 物件,而這敘述在大多數情況下都對」。其中「在大多數情況下都對」的理由,就是因為陣列也可以是有效的 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 資料完成範例吧。
在開始之前,先複製我們的 heroes.html 與 style.css 到你的本端硬碟中。後者包含某些簡易的 CSS 可塑造網頁風格;前者則提供極簡單主體 HTML:
<header> </header> <section> </section>
加上 {{HTMLElement("script")}} 元素,才能納入稍後會在此習題中寫出來的 JavaScript 程式碼。目前只有 2 行程式碼,用以取得 {{HTMLElement("header")}} 與 {{HTMLElement("section")}} 元素的參考,並將之儲存於變數之中:
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 載入至頁面,就要透過 {{domxref("XMLHttpRequest")}} API (通常稱為 XHR)。此是極好用的 JavaScript 物件,可讓網路請求透過 JavaScript (例如圖片、文字、JSON,甚至 HTML 片段) 來檢索伺幅器的資源,這也代表我們不需載入整個頁面,就能更新小部分的內容。如此可讓網頁反應速度更快;聽起來很棒吧?但可惜本文無法再深入講解更多細節。
var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
new 關鍵字,先從 XMLHttpRequest 建構子建立新的請求物件實例。把下列加到最後一行:
var request = new XMLHttpRequest();
open() 函式開啟新的請求。加入下列程式碼:
request.open('GET', requestURL);
這樣就顧到至少 2 個參數。當然也有其他參數可選擇。但這個簡易範例只需要 2 個強制參數:
GET 就可以。responseType,告知伺服器應回傳 JSON 物件,再以 send() 函式傳送請求:
request.responseType = 'json'; request.send();
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 資料吧。首先將下列函式定義加到先前的程式碼中:
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 組 {{HTMLElement("h1")}} 元素、將其 textContent 指定為 JSON 的 squadName 屬性、透過 appendChild() 將之附加到標頭。接著 {{HTMLElement("p")}} 元素依樣畫葫蘆一遍:建立、設定其文字內容、附加到標頭。唯一不同之處,就是將該文字設定為 1 組串接字串 (Concatenated string),其內包含 JSON 的 homeTown 與 formed 屬性。
現在將下列函式加到程式碼底端,用以建立並顯示超級英雄的卡片:
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 迴圈循環陣列中的各個物件。針對每個物件都會:
<article>、1 組 <h2>、3 組 <p>、1 組 <ul>。name。secretIdentity、age、Superpowers,在列表中帶出相關資訊。superPowers 儲存 powers 屬性 — 其中包含 1 組陣列以列出目前英雄的超能力。for 迴圈逐一巡過目前英雄的超能力。針對每一項超能力,我們再建立 1 組 <li> 元素,把超能力放進該元素之中,再透過 appendChild() 把 listItem 放入 <ul> 元素之內 (myList)。<article> (myArticle) 之內附加 <h2>、<p>、<ul>;再把 <article> 附加於 <section> 之內。這附加的順序極為重要,因為這也會是 HTML 中的顯示順序。注意:如果你無法讓此範例運作,可參閱我們的 heroes-finished.html 原始碼 (亦可看到實際執行情況。)
注意:如果你無法用我們說過的點記法 (dot-)\括弧記法 (bracket notation) 來存取 JSON,則可用新分頁或自己的文字編輯器開啟 superheroes.json 檔案並參考之。你也可再回去看看 JavaScript 物件基礎概念 ,再次了解點\括弧記法。
上述是存取 JSON 的簡易範例,因為我們設定要回傳響應的 XHR 已經是 JSON 格式。透過:
request.responseType = 'json';
但有時候沒這麼好運。我們有時會接收到文字字串格式的 JSON 資料,且必須將之轉換為物件。且當我們要以某種訊息傳送 JSON 資料時,也必須將之轉換為字串才能正確運作。還好,這 2 種問題在 Web 開發過程中甚為常見。內建的 JSON 物件很早就新增到瀏覽器之中,且包含下列 2 種函式:
parse():接收文字字串形式的 JSON 物件作為參數,並回傳對應的物件。stringify():接收 JSON 物件作為參數,並回傳對等的文字字串形式。你可到 heroes-finished-json-parse.html 範例 (參閱原始碼) 中看到第一個函式的運作情形。這其實跟我們先前範例所進行的事情一模一樣,不同之處在於我們設定 XHR 要回傳 JSON 為文字,接著再使用 parse() 轉換為實際的 JSON 物件。關鍵程式碼片段如下:
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 主控台上輸入下列程式碼,看看其運作方式:
var myJSON = { "name" : "Chris", "age" : "38" };
myJSON
var myString = JSON.stringify(myJSON);
myString
這樣就建立了 JSON 物件了。接著檢查內容物之後,就可透過 stringify() 將之轉換為字串。將回傳值儲存到新變數之中,再檢查一次即可。
我們透過本文簡單介紹了該如何在程式中使用 JSON、該如何建立\剖析 JSON、該如何存取其內的資料。接著就要說明物件導向 JavaScript (OOJS)。
{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}