1. 程式人生 > 實用技巧 >瞭解JSON.stringify()

瞭解JSON.stringify()

//JSON.stringify() 方法用於將 JavaScript 值轉換為 JSON 字串。

// ## 語法
// JSON.stringify(value[, replacer[, space]])

// - value:
// 必需, 要轉換的 JavaScript 值(通常為物件或陣列)。

// - replacer:
// 可選。用於轉換結果的函式或陣列。

// 如果 replacer 為函式,則 JSON.stringify 將呼叫該函式,並傳入每個成員的鍵和值。使用返回值而不是原始值。如果此函式返回 undefined,則排除成員。根物件的鍵是一個空字串:""。

// 如果 replacer 是一個數組,則僅轉換該陣列中具有鍵值的成員。成員的轉換順序與鍵在陣列中的順序一樣。

// - space:
// 可選,文字新增縮排、空格和換行符,如果 space 是一個數字,則返回值文字在每個級別縮排指定數目的空格,如果 space 大於 10,則文字縮排 10 個空格。space 也可以使用非數字,如:\t。

// 常用JSON.stringify()有那些=>資料的深拷貝

let obj = {
	a: '你好',
	b: '你好b',
	c: '防守打法c'
}

let obj1 = JSON.parse(JSON.stringify(obj))
obj1.a = "你好a"
console.log(obj) // {a: "你好", b: "你好b", c: "防守打法c"}
console.log(obj1) // {a: "你好a", b: "你好b", c: "防守打法c"}
console.log(JSON.stringify(obj)) // {"a":"你好","b":"你好b","c":"防守打法c"}


// ### 返回值
// 對於undefined、任意的函式,symbol作為物件屬性值的時候,JSON.stringify() 將跳過(忽略)對他們進行序列化
// 對於undefined、任意的函式以及 symbol 作為陣列元素值時,JSON.stringify() 將會將它們序列化為 null
// 對於undefined、任意的函式以及 symbol 被 JSON.stringify() 作為單獨的值進行序列化時,都會返回 undefined

const data = {
	a: "aaa",
	b: undefined,
	c: Symbol("dd"),
	fn: function() {
		return true;
	}
};

console.log(JSON.stringify(data)); // {"a":"aaa"}
console.log(JSON.parse(JSON.stringify(data)))

// 延伸問題:
// 物件裡的屬性值存在undefined如何去掉擁有undefined屬性值的屬性?


// ### 非陣列物件的屬性不能保證以特定的順序出現在序列化後的字串中
const data = {
  a: "aaa",
  b: undefined,
  c: Symbol("dd"),
  fn: function() {
    return true;
  },
  d: "ddd"
};
JSON.stringify(data); // 輸出:?
// "{"a":"aaa","d":"ddd"}"

JSON.stringify(["aaa", undefined, function aa() {
    return true
  }, Symbol('dd'),"eee"])  // 輸出:?
// "["aaa",null,null,null,"eee"]"

// JSON.stringify() 序列化時會忽略一些特殊的值,所以不能保證序列化後的字串還是以特定的順序出現(陣列除外)。

// ### 轉換值如果有 toJSON() 函式,該函式返回什麼值,序列化結果就是什麼值,並且忽略其他屬性的值。
JSON.stringify({
    say: "hello JSON.stringify",
    toJSON: function() {
      return "today i learn";
    }
  })
// "today i learn"

// ### JSON.stringify() 將會正常序列化 Date 的值

JSON.stringify({ now: new Date() });
// "{"now":"2019-12-08T07:42:11.973Z"}"

// 實際上 Date 物件自己部署了 toJSON() 方法(同Date.toISOString()),因此 Date 物件會被當做字串處理。

// ### NaN 和 Infinity 格式的數值及 null 都會被當做 null。

JSON.stringify(NaN)
// "null"
JSON.stringify(null)
// "null"
JSON.stringify(Infinity)
// "null"

// ### 迴圈引用報錯
// 對包含迴圈引用的物件(物件之間相互引用,形成無限迴圈)執行此方法,會丟擲錯誤。 
const obj = {
  name: "loopObj"
};
const loopObj = {
  obj
};
// 物件之間形成迴圈引用,形成閉環
obj.loopObj = loopObj;

// 封裝一個深拷貝的函式
function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}
// 執行深拷貝,丟擲錯誤
deepClone(obj)
/**
 VM44:9 Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'loopObj' -> object with constructor 'Object'
    --- property 'obj' closes the circle
    at JSON.stringify (<anonymous>)
    at deepClone (<anonymous>:9:26)
    at <anonymous>:11:13
 */