JSON.stringify馴服循環引用的對象
- 2020 年 3 月 26 日
- 筆記
在寫Tab組件持久化功能時:
localStorage.setItem('tabs',JSON.stringify(tabs))
遇到如下的報錯:

看意思應該是產生了循環引用的結構,經查閱資料和實踐做個記錄。
以下是不同瀏覽器對於這個類型錯誤報出錯的形式:
TypeError: cyclic object value (Firefox) TypeError: Converting circular structure to JSON (Chrome and Opera) TypeError: Circular reference in value argument not supported (Edge)
舉個例子?:
var circularReference = {otherData: 123}; circularReference.myself = circularReference;
此時到控制台裏面運行一下:
JSON.stringify(circularReference); // 報錯信息如下 VM685:1 Uncaught TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' --- property 'myself' closes the circle at JSON.stringify () at:1:6
可以看到和我上面說的Vue的例子是類似的。
那如何解決呢?
既然是由於循環引用導致的,那我們可以在發生循環引用的地方給切斷。
那如何切斷呢?
幸好JSON.stringify方法提供了便利,語法如下:
JSON.stringify(value[, replacer[, space]])
replacer可以作為一個函數傳入,且接受key和value作為入參,如下:
JSON.stringiify({},function(key,value){ // do sth })
那解決方案就有啦:
JSON.stringify(circularReference,function(key,value){ // 這裡的key的判斷條件,就是上面報錯信息里的 property 'xxx' closes the circle, // 這裡xxx是什麼條件就是什麼 if(key == 'myself'){ return } return value })
如果嫌麻煩還有更簡便的方法:
const getCircularReplacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); } return value; }; }
運行如下:
JSON.stringify(circularReference, getCircularReplacer()); // {"otherData":123}
再推薦幾個解決類似問題的庫:
- circular-json (現在只維護,vue-devtools內部也使用它)
- flatted (上面庫的繼承者)
- json-stringify-safe
- cycle.js