一个JSON解析器
来源
《JavaScript语言精粹(修订版)》
代码
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title></title> 7 </head> 8 9 <body> 10 <script> 11 var json_parse = function () { 12 var 13 at, 14 ch, 15 escapee = { 16 '"': '"', 17 '\\': '\\', 18 '/': '/', 19 b: 'b', 20 f: '\f', 21 n: '\n', 22 r: '\r', 23 t: '\t' 24 }, 25 text, 26 // 抛出异常 27 error = function (m) { 28 throw { 29 name: 'SyntaxError', 30 message: m, 31 at: at, 32 text: text 33 } 34 }, 35 // 获取下一个字符 36 next = function (c) { 37 if (c && c !== ch) { 38 error(`Expected ${c} instead of ${ch}`); 39 } 40 ch = text.charAt(at); 41 at += 1; 42 return ch; 43 }, 44 // 解析一个数字值 45 number = function () { 46 var number, string = ''; 47 // 负号 48 if (ch === '-') { 49 string = '-', 50 next('-') 51 } 52 // 整数 53 while (ch >= '0' && ch <= '9') { 54 string += ch; 55 next(); 56 } 57 // 小数 58 if (ch === '.') { 59 string += '.'; 60 while (next() && ch >= '0' && ch <= '9') { 61 string += ch; 62 } 63 } 64 // 指数 65 if (ch === 'e' || ch === 'E') { 66 string += ch; 67 next(); 68 if (ch === '-' || ch === '+') { 69 string += ch; 70 next(); 71 } 72 while (ch >= '0' && ch <= '9') { 73 string += ch; 74 next(); 75 } 76 } 77 number = +string; 78 if (isNaN(number)) { 79 error('Bad number') 80 } else { 81 return number; 82 } 83 }, 84 // 解析一个字符串值 85 string = function () { 86 var hex, 87 i, 88 string = '', 89 uffff; 90 // 字符串必须以双引号开始 91 if (ch === '"') { 92 while (next()) { 93 if (ch === '"') { 94 next(); 95 return string; 96 } else if (ch === '\\') { 97 next(); 98 // unicode码 99 if (ch === 'u') { 100 uffff = 0; 101 for (i = 0; i < 4; i++) { 102 hex = parseInt(next(), 16); 103 if (!isFinite(hex)) { 104 break; 105 } 106 ufff = ufff * 16 + hex; 107 } 108 string += String.fromCharCode(ufff) 109 } 110 else if (typeof escapee[ch] === 'string') { // 转义字符 111 string += escapee[ch] 112 } else { 113 break; 114 } 115 } else { 116 string += ch; 117 } 118 } 119 } 120 error('Bac string'); 121 }, 122 // 跳过空白 123 white = function () { 124 while (ch && ch <= ' ') { 125 next(); 126 } 127 }, 128 // 解析 true、false、null 129 word = function () { 130 switch (ch) { 131 case 't': 132 next('t'); 133 next('r'); 134 next('u'); 135 next('e'); 136 return true; 137 case 'f': 138 next('f'); 139 next('a'); 140 next('l'); 141 next('s'); 142 next('e'); 143 return true; 144 case 'n': 145 next('n'); 146 next('u'); 147 next('l'); 148 next('l'); 149 return true; 150 } 151 error(`Unexpected ${ch}`) 152 }, 153 // 解析一个数组值 154 array = function () { 155 var array = []; 156 if (ch === '[') { 157 next('['); 158 white(); 159 if (ch === ']') { 160 next(']'); 161 return array; 162 } 163 while (ch) { 164 array.push(value()); 165 white(); 166 if (ch === ']') { 167 next(']'); 168 return array; 169 } 170 next(','); 171 white(); 172 } 173 } 174 error('Bad array'); 175 }, 176 // 解析一个对象值 177 object = function () { 178 var key, object = {}; 179 if (ch === '{') { 180 next('{'); 181 white(); 182 if (ch === '}') { 183 next('}'); 184 return object; 185 } 186 while (ch) { 187 key = string(); 188 white(); 189 next(':'); 190 object[key] = value(); 191 white(); 192 if (ch === '}') { 193 next('}'); 194 return object; 195 } 196 next(','); 197 white(); 198 } 199 } 200 error('Bad object'); 201 }, 202 // 解析一个JSON值。它可以是对象、数组、字符串、数字、一个词。 203 value = function () { 204 white(); 205 switch (ch) { 206 case '{': 207 return object(); 208 case '[': 209 return array(); 210 case '"': 211 return string(); 212 case '-': 213 return number; 214 default: 215 return ch >= '0' && ch <= '9' ? number() : word(); 216 } 217 }; 218 // 返回json_parse函数 219 return function (source, reviver) { 220 var result; 221 text = source; 222 at = 0; 223 ch = ' '; 224 result = value(); 225 white(); 226 if (ch) { // 多余的非空白字符 227 error('Syntax error'); 228 } 229 return typeof reviver === 'function' ? function walk(holder, key) { 230 var k, v, value = holder[key]; 231 if (value && typeof value === 'object') { 232 // 递归处理对象的属性 233 for (k in value) { 234 if (Object.hasOwnProperty.call(value, k)) { 235 v = walk(value, k); 236 if (v !== undefined) { 237 value[k] = v; 238 } else { 239 delete value[k] 240 } 241 } 242 } 243 } 244 // 处理对象 245 return reviver.call(holder, key, value); 246 }({ '': result }, '') : result; 247 } 248 }(); 249 // \n是一个字符,\\n是两个字符 250 const str = '{"name":"饮料","price":2.5,"cool":true,"description":["雪碧","可乐"],"escapseSlash":"\\/","escapeN":"\\n"}'; 251 console.log(json_parse(str, (key, val) => val)) 252 </script> 253 </body> 254 255 </html>
运行结果