JSON 工具箱

JSON 解析與處理庫選型對照

結論:原生 API 最快,容錯解析帶偏移量,路徑查詢與補丁各管一段。選型看三件事:錯誤定位、是否破壞原文、邊界是否明確。

進階約 11 分鐘發佈於 2026-10-30更新於 2026-10-30
JSON 解析與處理庫選型對照封面

結論:先按用途分四類再看實現——只讀值用原生 JSON.parse,需要偏移量或保留原文格式用 jsonc-parser,查詢與補丁庫各自按需引入;體積大的庫按頁面動態匯入,長期不維護的庫直接排除。

每個庫都宣稱自己「快、小、全」。真正區分它們的是出錯時能告訴你多少資訊。

一、按用途分四類

類別 代表庫 解決什麼
標準解析 JSON.parse / JSON.stringify 語法 ↔ 物件,速度優先
容錯解析 + 編輯 jsonc-parser、json5 帶註釋的輸入、精確到偏移量的錯誤、保留格式的修改
查詢 jsonpath-plus、jsonpath 按表示式篩選節點
變更 fast-json-patch、immer 生成/應用補丁,不可變更新

先確定自己在哪一類,再比較具體實現,否則很容易拿查詢庫去幹解析的活。

二、橫向對照

庫 錯誤定位 容錯(註釋/尾逗號) 能否保留原文格式 適用場景
JSON.parse 只有訊息與位置(引擎相關) ✗ ✗ 預設解析、介面資料
jsonc-parser 精確 offset + 錯誤碼 ✓ ✓(modify + applyEdits) 編輯器、配置檔案
json5 行列資訊 ✓(更寬鬆) ✗ 讀取 JSON5 配置
jsonlint 行列資訊 ✗ ✗ 僅作參考,維護不活躍
jsonpath-plus 表示式語法錯誤 — — 按表示式查詢
fast-json-patch 操作級錯誤 — — 補丁生成與應用
lz-string — — — 把 JSON 壓縮排 URL

JSON.parse 的錯誤資訊在不同引擎差異很大。V8 會給出類似 Unexpected token } in JSON at position 42 的提示,但位置是否準確取決於引擎版本; jsonc-parser 則穩定返回結構化的 { error, offset, length },適合做編輯器標記。

三、四個關鍵決策點

3.1 需不需要偏移量

做編輯器、要做「點錯誤跳轉到對應行」就必須有 offset。判斷方法很簡單: 如果你的錯誤提示只能列印「JSON 格式錯誤」,使用者就得自己找半天。

import { parse, printParseErrorCode } from 'jsonc-parser';

const errors: Array<{ error: number; offset: number; length: number }> = [];
parse(text, errors, { allowTrailingComma: true, disallowComments: false });

if (errors.length > 0) {
  const firstError = errors[0];
  console.error(`${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`);
}

3.2 要不要保留原文

只想讀值 → 任何解析器都行。 要「改一個欄位、其餘原樣保留」→ 必須用編輯式 API,不能用「解析 → 改物件 → 序列化」。

後者會丟掉:註釋、鍵順序(部分實現)、縮排風格、數字字面量寫法(1e3 變 1000)、轉義形式(\u4e2d 變中文)。

3.3 邊界行為是否明確

選庫前查三件事的文件:

  1. 重複鍵怎麼處理(取最後一個 / 報錯);
  2. 大整數是否丟精度(多數 JS 庫會,因為都走 Number);
  3. BOM、註釋、尾逗號的支援範圍。

沒有文件說明的,就寫個小樣例實測。這比讀 README 更可靠。

3.4 維護狀態

JSON 庫的風險不在功能缺失,而在長期不維護:安全補丁(原型汙染、ReDoS)不會有人發。

四、其他語言的對照

語言 標準庫 / 主流庫 關鍵差異
JavaScript JSON.parse 數字一律雙精度
TypeScript 同上 + jsonc-parser / zod 型別只在編譯期
Go encoding/json 預設 float64,需 UseNumber() 保精度;json.RawMessage 延遲解析
Java Jackson / Gson / Moshi Jackson 需注意預設型別開啟的風險
Python json / orjson parse_float=Decimal 保精度;orjson 更快但不支援所有型別
Rust serde_json 強型別反序列化;arbitrary_precision 特性保精度
C++ simdjson / RapidJSON simdjson 面向解析吞吐,RapidJSON 更通用

跨語言交換時,最容易踩的還是數字精度與時間格式,庫的選擇只能緩解不能消除。

五、典型組合方案

方案 1:工具站(瀏覽器端)

解析與錯誤定位:jsonc-parser
編輯器:CodeMirror 6 + @codemirror/lang-json
查詢:jsonpath-plus
補丁:fast-json-patch
分享連結:lz-string

這套組合的特點是全在本地跑,不上傳資料,符合工具類站點的隱私預期。

方案 2:服務端介面閘道器

校驗:Ajv(schema 編譯一次,複用)
解析:原生 JSON.parse(配合 body 大小限制)
大欄位延遲解析:保留原始字串,用時再 parse

閘道器層不要引入查詢/補丁庫做業務邏輯,那是業務層的事。

方案 3:CLI 與指令碼

取欄位:jq
格式轉換:yq / dasel
互動瀏覽:jless
批次校驗:ajv-cli

六、體積與效能的實際影響

  • jsonc-parser 體積很小,適合進主包;
  • json5 比 jsonc-parser 略大,因為要支援更多語法;
  • jsonpath-plus 包含表示式求值,體積明顯更大,應隨頁面懶載入;
  • fast-json-patch 體積中等,只有對比功能時才需要。

最佳化手段很直接:按頁面動態匯入,別把它們塞進首屏 chunk。

const { JSONPath } = await import('jsonpath-plus');

七、檢查清單

  • [ ] 按用途選庫,不用查詢庫做解析;
  • [ ] 需要精確錯誤定位時用 jsonc-parser;
  • [ ] 需要保留註釋與格式時用編輯式 API;
  • [ ] 實測重複鍵、大整數、BOM 三個邊界行為;
  • [ ] 關注庫的維護狀態與安全通告;
  • [ ] 大體積庫按需動態匯入。

常見問題

如何依專案規模選擇 JSON 函式庫?

小到只讀介面資料的工具,用原生 JSON.parse 就夠;需要編輯器式錯誤定位或保留原文格式的中型專案,選 jsonc-parser;伺服器端閘道器只做校驗與解析,查詢和補丁庫留給業務層;CLI 與指令碼直接用 jq、yq、ajv-cli。按用途分類之後再比較具體實現,能避免拿查詢庫去幹解析的活。

為什麼維護狀態比功能多寡更值得關注?

JSON 庫真正的風險不在功能缺失,而在長期不維護:原型汙染、ReDoS 這類安全補丁不會有人發。功能再全,只要維護停擺,出問題時只能自己打補丁。選型時把維護狀態與安全通告當成硬指標,比對照功能表更有效。

能否用 JSON.parse 改欄位並保留註釋與縮排?

不能。「解析 → 改物件 → 序列化」會丟掉註釋、鍵順序、縮排風格、數字字面量寫法(1e3 變 1000)和轉義形式(\u4e2d 變中文)。要改一個欄位、其餘原樣保留,必須用 jsonc-parser 的 modify 與 applyEdits 這類編輯式 API。