JSON(JavaScript Object Notation)是一種輕量的數據格式,它不是一門編程語言。JSON是基於JavaScript Programming Language,Standard ECMA-262 3rd Edition - December 1999的一個子集。但 JSON
並不屬於 JavaScript
,不少編程語言都有針對 JSON
的解析器和序列化器。javascript
根據紅寶書中的介紹,JSON 有三種類型的值,分別爲簡單值、對象和數組。html
JavaScript
相同的語法,能夠在 JSON
中表示字符串、數值、布爾值和 null
。但 JSON
不支持 JavaScript
中的特殊值 undefined
在 JavaScript 中已經內置了 JSON
對象,它有 parse
和 stringify
兩個方法。java
在實際工做中,這兩個方法咱們也常常用到,例如實現對象深拷貝時編程
const obj = { name: 'Jay', age: 41 } const jsonStr = JSON.stringify(obj) // {"name":"Jay","age":41} const copiedObj = JSON.parse(jsonStr) // {name: "Jay", age: 41}
本文就來實現 JSON
的 parse
方法。json
parse
咱們先看一下 JSON
字符串的結構數組
const json = ` { "status": 100, "msg": "返回成功", "data": { "string": "abc", "array": [1,2,3], "children": [ { "name": "Jay", "age": 41, "occupation": "Musician"}, { "name": "Jack", "age": 56, "occupation": "CEO"}, { "name": "Kobe", "age": 42, "occupation": "Basketball players"} ] } } `;
咱們的函數就叫作 fakeParseJSON
,咱們先用原生方法跑一下編程語言
const fakeParseJSON = JSON.parse fakeParseJSON(json) // {status: 100, msg: "返回成功", data: {…}}
咱們先從簡單值開始來寫函數
值(value)能夠是雙引號括起來的字符串(string)、數值(number)、true
、false
、null
、對象(object)或者數組(array)。這些結構能夠嵌套。
流程圖以下:測試
以值爲 string
類型爲例spa
const str = ` "hello world" `
上面就是一個簡單的 JSON
值(value
),根據流程圖,從左往右會通過 whitespace
, "
, string
, "
, whitespace
。咱們就一個一個來處理。
function fakeParseJSON(str) { let i = 0 // 處理 whitespace, 遇到空格,回車,製表符等直接跳過 function parseWhiteSpace() { while(str[i] === ' ' || str[i] === '\n' || str[i] === '\r' || str[i] === '\t') { i++ } } function parseValue() { // 首先處理前面可能有的空格 parseWhiteSpace() // 處理 string if(str[i] === '"') { // 以雙引號開頭 i++ let res = '' while(str[i] !== '"') { res += str[i] i++ } // 繼續往下移 i++ return res } } }
測試一下
fakeParseJSON(str) // hello world
咱們的 JSON
值的類型不只有 string
,還有 number
, object
等類型。咱們最後要處理的都是 JSON
的 value
,並且咱們知道 value
是 object
類型是「名稱/值」對的集合形式,名稱通常都是字符串,值的話各類類型都有。在解析 JSON 對象時,咱們要處理名稱,這裏咱們先單獨抽離一個專門處理字符串的函數 parseString
,咱們改動一下代碼
function fakeParseJSON(str) { let i = 0 // 處理 whitespace, // ... // 處理字符串 function parseString() { parseWhiteSpace() if(str[i] === '"') { // 以雙引號開頭 i++ let res = '' while(str[i] !== '"') { res += str[i] i++ } // 繼續往下移 i++ return res } } // 處理結果 function parseValue() { return parseString() } // 輸出結果 return parseValue() }
接下來咱們來處理 JSON
對象,先看看流程圖
從圖中咱們能夠看出是以"{
" 開頭,"}
"結尾,中間可能會經歷 whitespace
, string
, :
, whitespace
, value
, ,
, ...
。咱們也先以值爲簡單類型的爲例
const obj = ` { "msg": "返回成功" } `
咱們也加上一個 parseObject
的函數
function fakeParseJSON(str) { let i = 0 // 處理 whitespace // ... // 處理冒號 function parseColon() { if(str[i] !== ":") { throw new Error('Expected ":".') } i++ } // 處理字符串 // ... // 處理對象 function parseObject() { parseWhiteSpace() if(str[i] === '{') { i++ parseWhiteSpace() const result = {} while(str[i] !== '}') { // 處理字符串 const key = parseString() parseWhiteSpace() parseColon() // 這裏新加一個處理冒號的 const value = parseValue() result[key] = value } i++ return result } } function parseValue() { parseWhiteSpace() const value = parseString() || parseObject() parseWhiteSpace() return value } return parseValue() }
測試一下
fakeParseJSON(obj) // {msg: "返回成功"}
咱們繼續豐富一下,在以前的 json
對象基礎上增長數組類型
const obj = ` { "msg": "返回成功", "arr": ["a","b","c"] } `;
這裏咱們有兩個任務要處理,其一是處理新增的 ,
,還有就是處理數組。
function fakeParseJSON(str) { let i = 0 // ... // 處理逗號 function parseComma() { if (str[i] !== ",") { throw new Error('Expected ",".'); } i++; } // 處理對象 function parseObject() { parseWhiteSpace() if(str[i] === '{') { // ... let initial = true while(str[i] !== '}') { if(!initial) { parseComma() // 處理逗號 parseWhiteSpace() } // ... initial = false } // ... } } // ... }
其二是處理數組,咱們看看數組的流程圖
和處理對象類型差很少,直接上代碼
function fakeParseJSON(str) { let i = 0 // ... // 處理數組 function parseArray() { if(str[i] === "[") { i++ parseWhiteSpace() const result = [] let initial = true while(str[i] !== "]") { if(!initial) { parseComma() parseWhiteSpace() } const value = parseValue() result.push(value) initial = false } i++ return result } } function parseValue() { parseWhiteSpace() const value = parseString() || parseObject() || parseArray() parseWhiteSpace() return value } return parseValue() }
處理 number
狀況比較麻煩,咱們也是先看一下流程圖
從圖中能夠看出,須要處理負數,小數以及指數等狀況
function fakeParseJSON(str) { let i = 0 // ... // 處理 number function parseNumber() { let start = i if (str[i] === "-") i++ if (str[i] === "0") { i++ } else if (str[i] >= "1" && str[i] <= "9") { i++ while (str[i] >= "0" && str[i] <= "9") { i++; } } if (str[i] === ".") { i++ while (str[i] >= "0" && str[i] <= "9") { i++ } } if (str[i] === "e" || str[i] === "E") { i++ if (str[i] === "-" || str[i] === "+") { i++ } while (str[i] >= "0" && str[i] <= "9") { i++ } } if (i > start) { return Number(str.slice(start, i)); } } function parseValue() { parseWhiteSpace() const value = parseString() || parseObject() || parseArray() || parseNumber() parseWhiteSpace() return value } // 輸出結果 return parseValue() }
咱們還差布爾值以及 null
的狀況
function fakeParseJSON(str) { let i = 0 // ... // true, false and null function parseKeyword(name, value) { if (str.slice(i, i + name.length) === name) { i += name.length; return value; } } function parseValue() { parseWhiteSpace() const value = parseString() || parseObject() || parseArray() || parseNumber() || parseKeyword("true", true) || parseKeyword("false", false) || parseKeyword("null", null) parseWhiteSpace() return value } // 輸出結果 return parseValue() }
至此,咱們大概實現了一個 JSON.parse
方法,固然還很不完善,好比字符串的處理以及容錯處理。
字符串(_string_)是由雙引號包圍的任意數量Unicode字符的集合,使用反斜線轉義。一個字符(character)即一個單獨的字符串(character string)。