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)。