美文网首页
JSON.stringify()的简单实现

JSON.stringify()的简单实现

作者: 浅忆_0810 | 来源:发表于2021-09-13 14:48 被阅读0次

1. JSON.stringify

1.1 基本概念

JSON.stringify 方法是将一个 JavaScript 对象或值转换为 JSON 字符串,默认该方法其实有三个参数:第一个参数是必选,后面两个是可选参数非必选。第一个参数传入的是要转换的对象;第二个是一个 replacer 函数,比如指定的 replacer 是数组,则可选择性地仅处理包含数组指定的属性;第三个参数用来控制结果字符串里面的间距

JSON.stringify({ x: [10, undefined, function () { }, Symbol('')] })  // '{"x":[10,null,null,null]}'

/* 第二个参数的例子 */
function replacer(key, value) {
  if (typeof value === "string") {
    return undefined;
  }

  return value;
}

var foo = { foundation: "Mozilla", model: "box", week: 4, transport: "car", month: 7 };
var jsonString = JSON.stringify(foo, replacer);
console.log(jsonString); // '{"week":4,"month":7}'

/* 第三个参数的例子 */
JSON.stringify({ a: 2 }, null, " ");
/*'{

 "a": 2

}'*/
JSON.stringify({ a: 2 }, null, ""); // '{"a":2}'

1.2 分析各种数据类型及边界情况

JSON.stringify 输入 输出
基础数据类型 undefined undefined
boolean 'false' / 'true'
number 字符串类型的数值
symbol undefined
null 'null'
string string
NaN 和 Infinity "null"
引用数据类型 function undefined
Array数组中出现了 undefined、function以及symbol string / "null"
RegExp "{}"
Date Date的 toJSON()字符串
普通 object 1. 如果有 toJSON() 方法,那么序列化 toJSON()的返回值<br />2. 如果属性值中出现了 undefined、任意的函数以及 symbol值,忽略<br />3. 所有以 symbol为属性键的属性都会被完全忽略掉

还有一个特殊情况需要注意:对于包含循环引用的对象(深拷贝那讲中也有提到)执行此方法,会抛出错误

1.3 代码逻辑实现

先利用 typeof 把基础数据类型和引用数据类型分开,分开之后再根据不同情况来分别处理不同的情况

function jsonStringify(data) {
  return typeof data !== 'object'
    ? isNotObject(data)
    : isObject(data)
}

function isNotObject(data) {
  let type = typeof data;

  switch (true) {
    // NaN 和 Infinity 序列化返回 "null"
    case Number.isNaN(data):
    case data === Infinity:
    case data === -Infinity:
      return "null"
 
    // 由于 function 序列化返回 undefined,因此和 undefined、symbol 一起处理
    case type === 'function':
    case type === 'undefined':
    case type === 'symbol':
      return undefined

    case type === 'string':
      return `"${data}"`

    default:
      return String(data);
  }
}

function isObject(data) {
  switch (true) {
    case data === null:
      return "null";

    case data.toJSON: 
    case typeof data.toJSON === 'function':
      return jsonStringify(data.toJSON());
    
    case data instanceof Array:
      let resultArr = [];

      // 如果是数组,那么数组里面的每一项类型又有可能是多样的
      data.forEach((item, index) => {
        resultArr[index] = (typeof item === 'undefined' || typeof item === 'function' || typeof item === 'symbol')
          ? "null"
          : jsonStringify(item);
      });
      return `[${resultArr}]`.replace(/'/g, '"');

    default:
      // 处理普通对象
      let result = [];

      Object.keys(data).forEach((item, index) => {
        if (typeof item !== 'symbol') {
          // key 如果是 symbol 对象,忽略
          if (data[item] !== undefined && typeof data[item] !== 'function' && typeof data[item] !== 'symbol') {
            // 键值如果是 undefined、function、symbol,忽略
            result.push(`"${item}":${jsonStringify(data[item])}`)
          }
        }
      });

      return `{${result}}`.replace(/'/g, '"');
  }
}
  1. 由于 function 返回 'null', 并且 typeof function 能直接返回精确的判断,故在整体逻辑处理基础数据类型的时候,随着 undefined,symbol 直接处理了
  2. 由于typeof null 的时候返回'object',故 null 的判断逻辑整体在处理引用数据类型的逻辑里面
  3. 关于引用数据类型中的数组,由于数组的每一项的数据类型又有很多的可能性,故在处理数组过程中又将 undefined,symbol,function 作为数组其中一项的情况做了特殊处理
  4. 同样在最后处理普通对象的时候,key (键值)也存在和数组一样的问题,故又需要再针对上面这几种情况(undefined,symbol,function)做特殊处理;
  5. 最后在处理普通对象过程中,对于循环引用的问题暂未做检测,如果是有循环引用的情况,需要抛出 Error;
  6. 根据官方给出的 JSON.stringify 的第二个以及第三个参数的实现,本段模拟实现的代码并未实现

1.4 测试

let nl = null;
console.log(jsonStringify(nl) === JSON.stringify(nl)); // true

let und = undefined;
console.log(jsonStringify(undefined) === JSON.stringify(undefined)); // true

let boo = false;
console.log(jsonStringify(boo) === JSON.stringify(boo)); // true

let nan = NaN;
console.log(jsonStringify(nan) === JSON.stringify(nan));
// true

let inf = Infinity;
console.log(jsonStringify(Infinity) === JSON.stringify(Infinity)); // true

let str = "jack";
console.log(jsonStringify(str) === JSON.stringify(str)); // true

let reg = new RegExp("\w");
console.log(jsonStringify(reg) === JSON.stringify(reg)); // true

let date = new Date();
console.log(jsonStringify(date) === JSON.stringify(date)); // true

let sym = Symbol(1);
console.log(jsonStringify(sym) === JSON.stringify(sym)); // true

let array = [1, 2, 3];
console.log(jsonStringify(array) === JSON.stringify(array)); // true

let obj = {
  name: 'jack',
  age: 18,
  attr: ['coding', 123],
  date: new Date(),
  uni: Symbol(2),
  sayHi: function () {
    console.log("hi")
  },
  info: {
    sister: 'lily',
    age: 16,
    intro: {
      money: undefined,
      job: null
    }
  }
}
console.log(jsonStringify(obj) === JSON.stringify(obj)) // true

2. JSON.parse

JSON.parse 方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象。该方法有两个参数:第一个参数是需要解析处理的 JSON 字符串,第二个参数是可选参数提供可选的 reviver 函数,用在返回之前对所得到的对象执行变换操作

const json = '{"result":true, "count":2}';

const obj = JSON.parse(json);
console.log(obj.count); // 2
console.log(obj.result);  // true

/* 带第二个参数的情况 */
JSON.parse('{"p": 5}', function (k, v) {
  if (k === '') return v;

  return v * 2;
});  // { p: 10 }

相关文章

网友评论

      本文标题:JSON.stringify()的简单实现

      本文链接:https://www.haomeiwen.com/subject/sfqfgltx.html