你不知道的JSON.stringify(上)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近使用 Vue 寫後臺管理系統,在做 Tab 組件的持久化時遇到一個問題:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c6/c64e6b6d2622965aa85d83c6d6771995.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看意思應該是產生了循環引用的結構,下面是不同瀏覽器對於這個類型錯誤報出錯的形式:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"TypeError: cyclic object value (Firefox)\nTypeError: Converting circular structure to JSON (Chrome and Opera)\nTypeError: Circular reference in value argument not supported (Edge)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉個例子🌰:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"var circularReference = {otherData: 123};circularReference.myself = circularReference;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此時到控制檯裏面運行一下:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"JSON.stringify(circularReference);\n\n// 報錯信息如下\nVM685:1 Uncaught TypeError: Converting circular structure to JSON\n --> starting at object with constructor 'Object'\n --- property 'myself' closes the circle\n at JSON.stringify ()\n at:1:6"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到和我上面說的 Vue 的例子是類似的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"那如何解決呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"既然是由於循環引用導致的,那我們可以在發生循環引用的地方給切斷。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"那如何切斷呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幸好 JSON.stringify 方法提供了便利,語法如下:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"JSON.stringify(value[, replacer[, space]])"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"replacer 可以作爲一個函數傳入,且接受 key 和 value 作爲入參,如下:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"\nJSON.stringiify({},function(key,value){\n // do sth\n})"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那解決方案就有啦:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"\nJSON.stringify(circularReference,function(key,value){\n if(key == 'myself'){ // 這裏的key的判斷條件,就是上面報錯信息裏的 property 'xxx' closes the circle,這裏xxx是什麼條件就是什麼\n return \n }\n return value\n})"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每次需要定位 key 值,如果嫌麻煩還有更簡便的方法:"}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"\nconst getCircularReplacer = () => {\n const seen = new WeakSet();\n return (key, value) => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return;\n }\n seen.add(value);\n }\n return value;\n };\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"推薦幾個解決類似問題的庫:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"circular-json (只維護,vue-devtools 內部也使用它)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"flatted (上面的繼承者)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"json-stringify-safe"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"cycle.js"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章