JSON.parser() 是JSON 格式的一個函數, 它用於將object 數據類型轉換成爲JSON 數據類型, 這裏咱們來本身實現一下JSON.parser() 函數.git
JSON 格式中, 能夠將須要處理數據類型分爲如下6類, 注意這裏的意思是須要處理的屬性類型有如下6 類, 表示的是數據處理的6 種狀況;
真實的數據分類並非按如下分類的, 這裏須要注意.github
本身實現一個函數, 用於判斷兩個對象是否相等, 實現代碼以下:json
// 判斷兩個對象是否相等的函數 const objectEquals = (a, b) => { // 若是 a, b相等,則返回 true,不然返回 false // Object.getOwnPropertyNames()方法返回一個由指定對象的全部自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值做爲名稱的屬性)組成的數組 // 換句話來講 Object.getOwnPropertyNames()方法返回的是對象全部 key 組成的數組 list var aProps = Object.getOwnPropertyNames(a) var bProps = Object.getOwnPropertyNames(b) if (aProps.length != bProps.length) { return false } for (var i = 0; i < aProps.length; i++) { var propName = aProps[i] if (typeof a[propName] === 'object') { let judge = objectEquals(a[propName], b[propName]) if (!judge) { return false } } else if (a[propName] !== b[propName]) { return false } } return true }
這裏匹配的字符串主要是括號的匹配, 理解下面的代碼數組
// 返回對象 '{' 對應的 '}',返回數組 '[' 對應的 ']' const getAimIndex = (string, index) => { let str = string // breakStr是結束判斷字符 let startStr = str[index] let breakStr = startStr === '{' ? '}' : ']' let judgeNum = 0 /* 判斷邏輯: 1. 遍歷從 i = 1 開始 2. if temp = '{' || '[', judgeNum++ 3. if temp = '}' || ']', judgeNum-- 4. if temp = '}' || ']' && judgeNum === 1, return i */ for (let i = index, len = str.length; i < len; i++) { let temp = str[i] if (temp === startStr) { judgeNum++ } else if (temp === breakStr && judgeNum !== 1) { judgeNum-- } else if (temp === breakStr && judgeNum === 1) { return i } } // log('judgeNum: ', judgeNum) } let str = '{{{}}}' console.log(getAimIndex(str, 0))
這個實現過程當中, 不少內容的實現都須要遞歸去完成, 所以對於遞歸有基本的瞭解會比較好理解.app
理解過程可能不會很費勁, 可是若是本身實現的話, 我的認爲若是可以將 Title2.2 判斷對象是否相等 獨立實現就能夠本身實現JSON.parse()函數
在生產tokens 數組中, 直觀上, 咱們會認爲咱們只須要將JSON 中有意義的字符串添加在tokens 數組中便可, 可是, 這樣作會存在一個問題:jsonp
對於以下代碼this
{ "obj1": true, "obj2": "true" }
上面代碼中, obj1 obj2 屬性本質上是不同的, 一個是String 類型, 一個是Boolean 類型, 而咱們從JSON 中讀取的內容類型均爲String 類型; 所以爲了確保完美解析JSON 數據, 咱們必須在tokens 數組中存儲JSON 數據的值類型prototype
同時, 因爲咱們生成對象的時候必須依賴值的類型, 值自己去生成對象, 所以須要提供一個方法返回值內容code
綜上所述, 咱們使用面向對象的思想來解決這個問題:
const log = console.log.bind(console) const TYPE = { "[object Number]": 1, "[object String]": 2, "[object Null]": 3, "[object Boolean]": 4, "character": 5, "escapeCharater": 6 } const includeEscapeCharacter = function(str) { let asciiEscape = [0, 39, 34, 92, 10, 13, 11, 9, 8, 12] for (let i = 0, len = str.length; i < len; i++) { let temp = str[i].charCodeAt(0) if (asciiEscape.indexOf(temp) !== -1) { return true } } return false } const dealEscape = (str) => { let escape = { b: `\b`, f: '\f', n: '\n', r: '\r', t: '\t', '\\': '\\', '\/': '\/', '\"': '\"', "\'": "\'" } let result = '' let string = str let i = 0 let len = string.length // log(str) while (i < len) { let temp = string[i] if (temp === '\\') { let endIndex = i + 1 result += escape[string[endIndex]] i = endIndex + 1 } else { result += temp i++ } } return result } const getType = function (value) { if (value === ':' || value === '{' || value === '}' || value === '[' || value === ']') { return 5 } if (includeEscapeCharacter(value)) { return 6 } let type = Object.prototype.toString.apply(value) return TYPE[type] } class JsonValue { constructor(value) { this.value = String(value) this.type = getType(value) } toString() { if (this.type === 1) { return Number(this.value) } else if (this.type === 2) { return String(this.value) } else if (this.type === 3) { return null } else if (this.type === 4) { return this.value === 'true' } else if (this.type === 5) { return String(this.value) } else if (this.type === 6) { return dealEscape(this.value) } } } const __main = () => { let a = new JsonValue('a') let b = new JsonValue(1) log(a) log(a.toString()) log(b) log(b.toString()) } __main()
tokens 數組中存儲的都是JsonValue 類型的數據;
接下來遍歷JSON 數據添加內容便可
這個過程就是遍歷tokens 數組, 依照符號(:)的索引index, tokens[index - 1] 爲key, tokens[index + 1] 爲value; 找到key-value 對, 而後添加到結果便可; 須要注意的是這個過程須要考慮Object 的嵌套, 以及Array中Object 的嵌套, 這裏須要使用遞歸去處理
這個過程的核心代碼以下: 根據不一樣的狀況, 處理不一樣的內容
// 獲取key-value對的value值 const getTokensValue = (index, array) => { let judge = array[index].value if (judge === '{') { let nextIndex = getAimIndex(array, index) let sliceList = array.slice(index + 1, nextIndex) return parsedDict(sliceList) } else if (judge === '[') { let nextIndex = getAimIndex(array, index) let sliceList = array.slice(index + 1, nextIndex) return conversionObj(sliceList) } else { return array[index].toString() } }
代碼地址: JSON.parse() 的實現