在真正去实现JSON.stringify的时候,我们先来关注一下,JSON.stringify函数的功能都有那些?只有真正懂得来JSON.stringify函数的功能,我们才能自己去实现一下JSON.stringify函数。


JSON.stringfy() 的说明

JSON.stringify()方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,如果指定了replacer是一个函数,则可以选择性的替换值,或者如果指定了replacer是一个数组,可选择性的仅包含数组指定的属性。
本文要实现的JSON.stringfy()是不带replacer和space参数的简化版本

转化过程遵循以下原则

  • 转换值如果有toJSON()方法,该方法定义什么值将被序列化。
  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined,如JSON.stringify(function(){})orJSON.stringify(undefined).
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
  • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便replacer参数中强制指定包含了它们。
  • Date日期调用了toJSON()将其转换为了string字符串(同Date.toISOString()),因此会被当做字符串处理。
  • NaN和Infinity格式的数值及null都会被当做null。
  • 其他类型的对象,包括Map/Set/weakMap/weakSet,仅会序列化可枚举的属性。

    转化例子

    ```javascript JSON.stringify({}); // ‘{}’ JSON.stringify(true); // ‘true’ JSON.stringify(“foo”); // ‘“foo”‘ JSON.stringify([1, “false”, false]); // ‘[1,”false”,false]’ JSON.stringify({ x: 5 }); // ‘{“x”:5}’

JSON.stringify({x: 5, y: 6});
// “{“x”:5,”y”:6}”

JSON.stringify([new Number(1), new String(“false”), new Boolean(false)]); // ‘[1,”false”,false]’

JSON.stringify({x: undefined, y: Object, z: Symbol(“”)}); // ‘{}’

JSON.stringify([undefined, Object, Symbol(“”)]);
// ‘[null,null,null]’

JSON.stringify({[Symbol(“foo”)]: “foo”});
// ‘{}’

JSON.stringify({[Symbol.for(“foo”)]: “foo”}, [Symbol.for(“foo”)]); // ‘{}’

JSON.stringify( {[Symbol.for(“foo”)]: “foo”}, function (k, v) { if (typeof k === “symbol”){ return “a symbol”; } } );

// undefined

// 不可枚举的属性默认会被忽略: JSON.stringify( Object.create( null, { x: { value: ‘x’, enumerable: false }, y: { value: ‘y’, enumerable: true } } ) ); // “{“y”:”y”}”

  1. <a name="uLEXT"></a>
  2. ## 知道执行的过程后, 如何手写一个JSON.stringify方法. 就变的很容易了.
  3. 代码如下:
  4. ```javascript
  5. /**
  6. * 手写源码:JSON.parse和JSON.stringify(不带replacer和space参数的简化版本)
  7. */
  8. const JSON = {
  9. parse: function(jsonStr) {
  10. return eval(`(${jsonStr})`);
  11. },
  12. stringify: function(jsonStr) {
  13. switch(Object.prototype.toString.call(jsonStr)) {
  14. case '[object Null]':
  15. case '[object Boolean]':
  16. case '[object Number]':
  17. return String(jsonStr)==="NaN" ? String(null) : String(jsonStr);
  18. case '[object String]':
  19. case '[object Date]':
  20. return `"${jsonStr.toJSON ? jsonStr.toJSON() : jsonStr.toString()}"`;
  21. case '[object Object]':
  22. let resultObj = '{';
  23. for(key in jsonStr) {
  24. if(this.stringify(key) !== undefined && this.stringify(jsonStr[key]) !== undefined) {
  25. resultObj += `"${key}":${this.stringify(jsonStr[key])},`;
  26. }
  27. }
  28. resultObj = resultObj.length > 1? resultObj.slice(0, -1): resultObj;
  29. return resultObj += '}';
  30. case '[object Array]':
  31. let resultArr = '[';
  32. for(item of jsonStr) {
  33. resultArr += (this.stringify(item) === undefined ? null : this.stringify(item)) + ",";
  34. }
  35. resultArr = resultArr.length > 1? resultArr.slice(0, -1): resultArr;
  36. return resultArr += ']';
  37. case '[object Set]':
  38. case '[object Map]':
  39. case '[object RegExp]':
  40. return "{}";
  41. case '[object Undefind]':
  42. case '[object Function]':
  43. case '[object Symbol]':
  44. return undefined;
  45. }
  46. }
  47. }

测试一下.

  1. // 测试后发现以下与原生体现不符,没搞明白为什么
  2. JSON.stringify(
  3. {[Symbol.for("foo")]: "foo"},
  4. function (k, v) {
  5. if (typeof k === "symbol"){
  6. return "a symbol";
  7. }
  8. }
  9. );
  10. //原生: undefined, 我的实现:"{}"

我们发现原生序列化和自实现的返回值, 不一样
image.png

参考文章(拷贝文章)

手写源码系列(三)——JSON.stringfy和JSON.parse
MDN之JSON.stringify