js jsonParse

const rx_one = /^[\],:{}\s]*$/;
const rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;

// 匹配合法json符号
// "asd" or 1.23 or 1.3e4 or 1.3e-4 or 1.3e+4 or -10 之类的
const rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;

// :[
// ,[
const rx_four = /(?:^|:|,)(?:\s*\[)+/g;

// 一些符号的unicode表示法
const rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

export function jsonParse(text: string, reviver?: Function): any {
  // 接受一个文本和一个可选的reviver函数,然后返回
  // 如果文本是有效的JSON文本,则为JavaScript值

  let j;
  function walk(holder: any, key: any) {
    // walk方法用于递归遍历结果结构,因此可以进行修改。
    let k: string | number;
    let v: any;
    let value = holder[key];
    if (value && typeof value === "object") {
      // {} or []
      for (k in value) {
        if (Object.prototype.hasOwnProperty.call(value, k)) {
          v = walk(value, k);
          if (v !== undefined) {
            value[k] = v;
          } else {
            delete value[k];
          }
        }
      }
      return reviver?.call(holder, key, value);
    }
  }

  // 解析分为四个阶段。 在第一阶段,我们替换某些
  // 具有转义序列的Unicode字符。 JavaScript处理许多字符
  // 错误地将其静默删除,或将其视为行尾。
  text = String(text);

  rx_dangerous.lastIndex = 0;
  if (rx_dangerous.test(text)) {
    // 转义序列的Unicode字符
    text = text.replace(rx_dangerous, function(match) {
      return "\\u" + ("0000" + match.charCodeAt(0).toString(16)).slice(-4);
    });
  }

  // 在第二阶段,我们针对看起来像正则表达式的文本
  // 用于非JSON模式。 我们特别关注"()"和"new"
  // 因为它们会引起调用,而"="则可能导致突变
  // 但是为了安全起见,我们要拒绝所有意外的形式。

  // 为了解决此问题,我们将第二阶段分为4个正则表达式操作
  // 严重影响IE和Safari的regexp引擎的效率低下。 首先我们
  // 将JSON反斜杠对替换为"@"(非JSON字符)。 第二,我们
  // 用"]"字符替换所有简单值标记。 第三,我们删除所有
  // 用冒号或逗号或文本开头的方括号。 最后,
  // 我们希望看到其余字符只是空格或"]"或
  // "."或":"或"{"或"}". 如果是这样,那么该文本对于eval是安全的。

  if (
    rx_one.test(
      /*`{"name": "ajanuw"}` => `{]: ]}` */
      text
        .replace(rx_two, "@")
        .replace(rx_three, "]")
        .replace(rx_four, "")
    )
  ) {
    // 在第三阶段,我们使用eval函数将文本编译为
    // JavaScript结构。 "{"运算符存在句法歧义
    // 在JavaScript中:它可以开始一个块或一个对象文字。 我们包装文字
    // 尽可能消除歧义
    j = eval(`(${text})`);

    // 在可选的第四阶段,我们递归遍历新结构,
    // 每个名称/值对到reviver函数进行可能的转换
    return typeof reviver === "function"
      ? walk(
          {
            "": j
          },
          ""
        )
      : j;
  }
  // 如果文本不是JSON可解析的,则抛出SyntaxError。
  throw new SyntaxError("json parse error!!");
}

const r = jsonParse(`{"name": "ajanuw"}`);
console.log({ result: r });
posted @ 2020-02-27 14:48  Ajanuw  阅读(236)  评论(0编辑  收藏  举报