National Chengchi University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

政治大學 AQI 58 25°C PM2.5 12
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 10

JSON 與複製

JSON 規則、stringify、parse 與淺複製和深複製
Interaction實作 20 minute(s)

Learning Objectives

  • 說明 JSON 的用途與語法規則,分辨 JSON 字串與 JavaScript 物件字面值
  • 用 JSON.parse 把 JSON 字串轉成物件,並用 try…catch 處理格式錯誤
  • 用 JSON.stringify 把物件轉成 JSON 字串,說明 undefined、函式、Date 會怎麼處理
  • 分辨指定、淺複製與深複製,用展開、Object.assign、JSON 往返與 structuredClone 複製資料

JSON:交換資料用的文字格式

JSON(JavaScript Object Notation,JavaScript 物件表示法)是一種用文字表示資料的格式。 網頁向伺服器要資料、程式儲存設定檔、不同程式語言之間交換資料,最常用的就是 JSON。 它的寫法源自 JavaScript 的物件與陣列,但現在幾乎所有程式語言都有讀寫 JSON 的函式庫。

{
  "course": "JavaScript",
  "hours": 30,
  "online": true,
  "teacher": { "name": "Amy" },
  "tags": ["web", "frontend"],
  "room": null
}
  • 物件用 { },裡面是「鍵: 值」,用逗號分隔;陣列用 [ ]
  • 整份 JSON 可以是一個物件,也可以是一個陣列(或單一的值)
  • 取資料的方式和 JavaScript 一樣:轉成物件之後,data.teacher.name、data.tags[0]

JSON 比物件字面值嚴格

JSON 長得很像 JavaScript 的物件字面值,但規則嚴格許多:

規則 JSON JavaScript 物件字面值
鍵 一定要用雙引號:"name" 可以不加引號:name
字串 一定用雙引號 "…" 單引號、雙引號、反引號都可以
最後一個元素後面的逗號 不可以 可以
註解 不可以 可以
值的型別 字串、數字、true/false、null、物件、陣列 任何值,包括函式、undefined、Date

兩者的身分也不同:JSON 是一段字串(typeof 得到 'string'),要先用 JSON.parse 轉成物件才能取屬性; 物件字面值寫在程式裡,本身就是物件。

方法 方向
JSON.parse(text) JSON 字串 → JavaScript 的值
JSON.stringify(value) JavaScript 的值 → JSON 字串

JSON.parse:字串變成物件

text 只是一段字串,右邊顯示它的值是一長串文字。第 6 行 JSON.parse 之後,heroes 變成真正的陣列,裡面有兩個物件,可以一層一層取值。

JSON.stringify:哪些東西會不見

JSON.stringify 把值轉成 JSON 字串,遇到 JSON 沒有的型別時會這樣處理:

值 在物件的屬性裡 在陣列裡
undefined、函式、Symbol 整個屬性被省略 變成 null
NaN、Infinity 變成 null 變成 null
Date 變成 ISO 格式的字串(例如 "2026-10-29T00:00:00.000Z",以 UTC 表示) 同左

所以 JSON.parse(JSON.stringify(x)) 之後,日期會變成字串、方法會消失。

JSON.stringify(value, replacer, space) 還有兩個選擇性參數:

  • space:縮排,數字代表幾個空白(最多 10),讓輸出比較好讀,例如 JSON.stringify(data, null, 2)
  • replacer:一個函式或屬性名稱的陣列,用來決定哪些屬性要輸出、要怎麼轉換

JSON.parse(text, reviver) 也可以給一個 reviver 函式,在解析時轉換每一個值。

stringify 的規則

data 裡有 undefined、一個方法、一個 Date 和含有 undefined、NaN 的陣列。看第 15 行印出的字串少了什麼、變了什麼。

格式錯誤時,JSON.parse 會丟出錯誤

五段字串只有兩段是合法的 JSON。單引號、鍵沒有引號、最後多一個逗號,在 JavaScript 物件字面值都可以,在 JSON 都不行。

想一想:JSON 的規則

1.

下面的程式會印出什麼?

const s = JSON.stringify({ a: 1, b: undefined, c: [undefined] });
console.log(s);
2.

下列哪一段是合法的 JSON?

3.

下面的程式會印出什麼?

const text = '{"n": 5}';
console.log(typeof text, typeof JSON.parse(text).n);
第 1 次作答

指定、淺複製與深複製

第 8、9 課提過:物件與陣列是參照。要「複製」時,有三種程度:

做法 例子 外層是新的嗎 內層的物件
指定 const b = a 不是,同一個 同一個
淺複製(shallow copy) { ...a }、Object.assign({}, a)、[...arr]、arr.slice() 是 還是同一個
深複製(deep copy) structuredClone(a)、JSON.parse(JSON.stringify(a)) 是 也是新的

基本型別(數字、字串、布林值)沒有這個問題:let num2 = num1 就是複製值,之後改 num1 不影響 num2。

淺複製只複製第一層的屬性。如果屬性值是物件或陣列,新舊兩份共用同一個內層物件,透過任何一邊修改內層,另一邊也會看到。 資料只有一層、或內層不會被修改時,淺複製就夠用了。

淺複製:內層物件是共用的

播放到第 12 行時看右邊的箭頭:same 和 original 指向同一個物件;shallow、assigned 是新的物件,但它們的 inner 都指向同一個 {b: 20}。

深複製的兩種作法

JSON 往返:JSON.parse(JSON.stringify(a)) 先轉成字串再轉回來,得到的每一層都是新的。寫法簡單,但受 JSON 規則限制: 函式與 undefined 會不見、Date 會變成字串、NaN 會變成 null。

structuredClone:瀏覽器與 Node.js 內建的深複製函式,structuredClone(a)。它能正確複製 Date、Map、Set 等型別, 也能處理物件互相參照的情況;但不能複製函式(以及網頁元素等),遇到時會丟出 DataCloneError。 主要瀏覽器從 2022 年起都已支援,現在建議優先使用它。

投影片示範的另一種作法是用迴圈把每個屬性一一複製到新物件。只複製一層就是淺複製;要深複製,遇到內層物件時要再對它重複同樣的步驟。

深複製:JSON 往返與 structuredClone

第 6、7 行修改了原本的 a,但兩份深複製都不受影響:右邊的 viaJson、viaClone 各自有自己的內層物件。第 14、15 行比較兩種作法處理 Date 的差別。

想一想:複製

1.

下面的程式會印出什麼?

const a = { x: 1, inner: { y: 1 } };
const b = { ...a };
b.x = 2;
b.inner.y = 2;
console.log(a.x, a.inner.y);
2.

下面的程式會印出什麼?

const a = { list: [1, 2] };
const b = JSON.parse(JSON.stringify(a));
b.list.push(3);
console.log(a.list.length, b.list === a.list);
3.

要深複製 { when: new Date(), tags: ['a'] },而且複製後的 when 仍然要是 Date,用哪一個?

第 1 次作答

實作:解析 JSON 並轉換欄位

text 是一段 JSON,sex 用 1、0 表示男、女,married 用 true、false 表示已婚、未婚。請用 JSON.parse 解析,再逐筆印出「姓名,性別,婚姻狀態,城市」。

你的輸出
預期輸出

重點精華回顧

  • JSON 是交換資料用的文字格式:物件用 { }、陣列用 [ ],鍵與字串一律雙引號,不能有結尾逗號與註解。
  • JSON.parse 把 JSON 字串轉成 JavaScript 的值;格式錯誤會丟出 SyntaxError,要用 try…catch 處理。
  • JSON.stringify 把值轉成 JSON 字串:undefined 與函式被省略(在陣列裡變成 null)、Date 變成 ISO 字串;第三個引數可以縮排。
  • 指定(b = a)不會複製;淺複製(展開、Object.assign、slice)只複製第一層,內層物件仍共用。
  • 深複製連內層都複製:structuredClone 保留 Date 等型別但不能複製函式;JSON 往返簡單,但會失去函式並把日期變成字串。
這一課完成了!
Next lesson:函式
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。