मैं JSON जैसे प्रारूप में एक परिपत्र संरचना कैसे प्रिंट कर सकता हूं?


680

मेरे पास एक बड़ी वस्तु है जिसे मैं JSON में कनवर्ट करना और भेजना चाहता हूं। हालाँकि इसकी परिपत्र संरचना है। मैं चाहता हूं कि जो भी सर्कुलर रेफरेंस मौजूद हैं उसे टॉस करें और जो भी कड़ा हो सके उसे भेजें। मैं उसको कैसे करू?

धन्यवाद।

var obj = {
  a: "foo",
  b: obj
}

मैं obj को कठोर बनाना चाहता हूं:

{"a":"foo"}

5
क्या आप एक परिपत्र संदर्भ के साथ एक नमूना वस्तु पोस्ट कर सकते हैं जिसे आप पार्स करना चाहते हैं?
ट्विकज

3
की तरह कुछ इस ?
एल्विन वोंग


2
पार्टी के लिए देर हो चुकी है लेकिन इसे संभालने के लिए एक गीथब प्रोजेक्ट है।
प्रेस्टन एस

निकटता से संबंधित प्रश्न: stackoverflow.com/questions/23117470/…
mathheadinclouds कल

जवाबों:


605

JSON.stringifyकस्टम प्रतिकृति के साथ उपयोग करें । उदाहरण के लिए:

// Demo: Circular reference
var circ = {};
circ.circ = circ;

// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
JSON.stringify(circ, (key, value) => {
  if (typeof value === 'object' && value !== null) {
    // Duplicate reference found, discard key
    if (cache.includes(value)) return;

    // Store value in our collection
    cache.push(value);
  }
  return value;
});
cache = null; // Enable garbage collection

इस उदाहरण में प्रतिकृति 100% सही नहीं है ("डुप्लिकेट" की आपकी परिभाषा के आधार पर)। निम्नलिखित मामले में, एक मान छोड़ दिया गया है:

var a = {b:1}
var o = {};
o.one = a;
o.two = a;
// one and two point to the same object, but two is discarded:
JSON.stringify(o, ...);

लेकिन अवधारणा खड़ी है: एक कस्टम प्रतिकृति का उपयोग करें, और पार्स की गई ऑब्जेक्ट मानों पर नज़र रखें।

एक उपयोगिता कार्य के रूप में es6 में लिखा है:

// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
  let cache = [];
  const retVal = JSON.stringify(
    obj,
    (key, value) =>
      typeof value === "object" && value !== null
        ? cache.includes(value)
          ? undefined // Duplicate reference found, discard key
          : cache.push(value) && value // Store value in our collection
        : value,
    indent
  );
  cache = null;
  return retVal;
};

// Example:
console.log('options', JSON.safeStringify(options))

1
@ हेरी क्या बग है? मैं ख़ुशी से जवाब को ठीक करूँगा, अगर इसमें कोई अशुद्धि हो।
रॉब डब्ल्यू

1
@CruzDiablo Serializing DOM आमतौर पर अर्थहीन है। हालाँकि, यदि आप अपने उद्देश्यों के लिए एक सार्थक क्रमांकन विधि के बारे में सोच सकते हैं, तो आप डोम ऑब्जेक्ट्स में एक कस्टम क्रमांकित जोड़ने का प्रयास कर सकते हैं: Node.prototype.toJSON = function() { return 'whatever you think that is right'; };(यदि आप कुछ अधिक सामान्य / विशिष्ट चाहते हैं, तो प्रोटोटाइप पेड़ में कुछ भी आज़माएं: HTMLDivElementment औजार HTMLElement लागू करें तत्व इम्प्लिमेंट्स नोड इम्प्लीमेंट्स इवेंटटार्ग; नोट: यह ब्राउजर पर निर्भर हो सकता है, पिछला पेड़ क्रोम के लिए सही है)
रोब डब्ल्यू

7
यह गलत है क्योंकि यह उन वस्तुओं के दूसरे स्वरूप को छोड़ देगा जो दो बार निहित हैं, भले ही वह वास्तव में चक्रीय संरचना में न हो। var a={id:1}; JSON.stringify([a,a]);
user2451227

3
@ user2451227 "इस उदाहरण में प्रतिकृति 100% सही नहीं है (" डुप्लिकेट "की आपकी परिभाषा के आधार पर)। लेकिन अवधारणा खड़ी है: एक कस्टम प्रतिकृति का उपयोग करें, और पार्स की गई ऑब्जेक्ट मानों पर नज़र रखें।"
रॉब डब्ल्यू

4
यहाँ जीसी चिंता यकीनन बेमानी है। यदि इसे एकल स्क्रिप्ट के रूप में चलाया जाता है तो स्क्रिप्ट तुरंत समाप्त हो जाती है। यदि इसे क्रियान्वयन के लिए किसी फ़ंक्शन के अंदर इनकैप्सुलेट किया जाता है तो cacheअप्राप्य डेवलपर
pmillailla.org/en-US/docs/Web/JavaScript/…

704

Node.js में, आप use.inspect (ऑब्जेक्ट) का उपयोग कर सकते हैं । यह स्वचालित रूप से "[परिपत्र]" के साथ परिपत्र लिंक की जगह लेता है।


यद्यपि बिल्ट-इन (कोई स्थापना आवश्यक नहीं है) , आपको इसे आयात करना होगा

import * as util from 'util' // has no default export
import { inspect } from 'util' // or directly
// or 
var util = require('util')
इसका उपयोग करने के लिए, बस कॉल करें
console.log(util.inspect(myObject))

यह भी ध्यान रखें कि आप निरीक्षण करने के लिए विकल्प ऑब्जेक्ट पास कर सकते हैं (ऊपर लिंक देखें)

inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])



कृपया, नीचे टिप्पणी करने वालों को यश पढ़ें और दें ...


134
उपयोग एक अंतर्निहित मॉड्यूल है, आपको इसे स्थापित करने की आवश्यकता नहीं है।
मेटर

10
कंसोल.लॉग (यूसेज.इनस्पेक्ट (ओब्ज))
स्टारिनमपाइप्स

19
@ मेरा यह बिल्ट-इन है, लेकिन आपको अभी भी मॉड्यूल लोड करना हैvar util = require('util');
बोडेकर

14
मेरे जैसा नहीं है, इसके बस obj_str = util.inspect(thing) नहीं, नहीं <s> garbage_str = JSON.stringify(util.inspect(thing))/
ThorSummoner

7
यह जाँच प्रकारों के साथ घूमने से बहुत बेहतर है। क्यों इस तरह से काम नहीं कर सकते? अगर यह जानता है कि एक परिपत्र संदर्भ है, तो इसे अनदेखा करने के लिए सिर्फ क्यों नहीं कहा जा सकता है ???
क्रिस मोर

141

मुझे आश्चर्य है कि एमडीएन पृष्ठ से अभी तक किसी ने उचित समाधान क्यों नहीं पोस्ट किया ...

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());

सीन वैल्यू को एक सेट में संग्रहित किया जाना चाहिए , न कि एरे में ( प्रत्येक तत्व पर रिप्लेस्टर को बुलाया जाता है ) और चेन में JSON.stringify प्रत्येक तत्व को एक परिपत्र संदर्भ की ओर ले जाने की कोशिश करने की आवश्यकता नहीं है ।

स्वीकृत उत्तर की तरह, यह समाधान सभी दोहराए गए मूल्यों को हटाता है , न कि केवल परिपत्र लोगों को। लेकिन कम से कम इसमें घातीय जटिलता नहीं है।


नीट, लेकिन यह केवल ES2015 है। कोई IE समर्थन नहीं है।
मार्टिन कैपोडिसी

43
योदा का कहना है: "यदि अभी भी IE एक का समर्थन कर रहा है, तो एक ट्रांसपिलर का उपयोग करना चाहिए।"
स्पेन ट्रेन

1
replacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); } return value; }; } () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); … JSON.stringify({a:1, b: '2'}, replacer)undefinedक्रोम में वापसी
roberto tomás

1
यह रिएक्ट + टाइपस्क्रिप्ट में काम करता है। धन्यवाद
user3417479

76

बस करो

npm i --save circular-json

तो अपने जे एस फ़ाइल में

const CircularJSON = require('circular-json');
...
const json = CircularJSON.stringify(obj);

https://github.com/WebReflection/circular-json

नोट: मेरा इस पैकेज से कोई लेना-देना नहीं है। लेकिन मैं इसके लिए इसका इस्तेमाल करता हूं।

अद्यतन 2020

कृपया ध्यान दें कि CircularJSON केवल रखरखाव में है और चपटा इसके उत्तराधिकारी है


आपका बहुत बहुत धन्यवाद! महान पुस्तकालय, समय के टन बचाया। सुपर टिनी (सिर्फ 1.4KB की मिनीफाइड)।
ब्रायन हाक

16
मुझे लगता है कि आपको "बस करो" की तुलना में मॉड्यूल का उपयोग करने के लिए कुछ और औचित्य की आवश्यकता हो सकती है। और यह JSONसिद्धांत पर अधिलेखित करने के लिए महान नहीं है ।
एडविन

स्टब परीक्षण के लिए उपयोग करने के लिए मुझे एक वस्तु की प्रतिलिपि बनाने की आवश्यकता थी। यह उत्तर एकदम सही था। मैंने ऑब्जेक्ट को कॉपी किया और फिर ओवरराइड को हटा दिया। धन्यवाद!!
क्रिस शार्प

1
लेखक के अनुसार, इस पैकेज को हटा दिया गया है। CircularJSON केवल रखरखाव में है, चपटा इसका उत्तराधिकारी है। लिंक: github.com/WebReflection/flatted#flatted
रॉबर्ट मोलिना

3
खबरदार, 'चपटा' (और वृत्ताकार- json?) पैकेज JSON.stringify () कार्यक्षमता को दोहराता नहीं है। यह अपना गैर-JSON प्रारूप बनाता है। (उदाहरण के लिए, Flatted.stringify({blah: 1})परिणाम [{"blah":1}]) मुझे लगता है कि किसी ने इस बारे में एक मुद्दा उठाने की कोशिश की, और लेखक ने उन्हें उत्तेजित किया और टिप्पणी के लिए मुद्दे को बंद कर दिया।
jameslol

48

मुझे वास्तव में ट्रिंडाज़ का समाधान पसंद आया - अधिक क्रिया, हालांकि इसमें कुछ कीड़े थे। मैंने उन्हें तय किया कि जो कोई भी इसे पसंद करता है।

साथ ही, मैंने अपने कैश ऑब्जेक्ट्स पर एक लंबाई सीमा जोड़ी।

यदि मैं जिस ऑब्जेक्ट को प्रिंट कर रहा हूं वह वास्तव में बड़ा है - मेरा मतलब है कि असीम रूप से बड़ा है - मैं अपने एल्गोरिथ्म को सीमित करना चाहता हूं।

JSON.stringifyOnce = function(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
        return 'object too long';
        }
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if ( key == ''){ //root element
             printedObjects.push(obj);
            printedObjectKeys.push("root");
             return value;
        }

        else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
            if ( printedObjectKeys[printedObjIndex] == "root"){
                return "(pointer to root)";
            }else{
                return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase()  : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
            }
        }else{

            var qualifiedKey = key || "(empty key)";
            printedObjects.push(value);
            printedObjectKeys.push(qualifiedKey);
            if(replacer){
                return replacer(key, value);
            }else{
                return value;
            }
        }
    }
    return JSON.stringify(obj, printOnceReplacer, indent);
};

आपको इस लाइन पर एक अशक्त जाँच याद आ रही है: "" (देखें "+ (!! value.constructor? Value.constructor.name.toLowerCase (): typeof (मान)) +" कुंजी के साथ "+ मुद्रितObjectereys [PrintObjIndex] + ")";
इसक

मैं ख़ुशी से इसे जोड़ूंगा। बस मुझे पता है कि क्या अशक्त है क्योंकि मैंने अब तक किसी भी समस्या का अनुभव किया है।
आदमी मोगरबी

2
// ब्राउज़र 20K से अधिक प्रिंट नहीं करेंगे - लेकिन आपने सीमा को 2k के रूप में रखा है। शायद भविष्य के लिए बदल जाए?
पॉंच

38

@ रॉब का जवाब सही है, लेकिन यह अधिक प्रदर्शन करने वाला है! क्योंकि यह एक हैशमैप / सेट का उपयोग करता है:

const customStringify = function (v) {
  const cache = new Set();
  return JSON.stringify(v, function (key, value) {
    if (typeof value === 'object' && value !== null) {
      if (cache.has(value)) {
        // Circular reference found
        try {
          // If this value does not reference a parent it can be deduped
         return JSON.parse(JSON.stringify(value));
        }
        catch (err) {
          // discard key if value cannot be deduped
         return;
        }
      }
      // Store value in our set
      cache.add(value);
    }
    return value;
  });
};

परिपत्र संदर्भ के साथ गहरी नेस्टेड ऑब्जेक्ट्स के लिए, stringifyDeep => github.com/ORESoftware/safe-stringify
अलेक्जेंडर मिल्स

यह संभवतः है कि सेट कार्यान्वयन सिर्फ एक सरणी और अनुक्रमक का उपयोग करता है हुड के नीचे, लेकिन मैंने इसकी पुष्टि नहीं की है।
अलेक्जेंडर मिल्स

यह माता-पिता के नोड्स को अलग-अलग मूल्यों के साथ भी बच्चे के नोड्स को हटा रहा है - जैसे - {"a":{"b":{"a":"d"}}}और यहां तक ​​कि खाली ऑब्जेक्ट को हटाने वाले {}
संदीप पिंगल

क्या आप उस संदीप का उदाहरण दिखा सकते हैं? gist.github.com या whatnot बनाएँ
अलेक्जेंडर मिल्स

अति उत्कृष्ट !!! पहले (ऊपर से, लेकिन केवल 2-3 फ़ंक्शन समाधानों की जांच की गई) नोड के तहत काम कर रहे समाधान। जेएस और विखंडन; ;-) - पुस्तकालयों को लटका दिया।
टॉम

37

ध्यान दें कि JSON.decycleडगलस क्रॉकफोर्ड द्वारा कार्यान्वित एक विधि भी है । उसका चक्र देखें । js यह आपको लगभग किसी भी मानक संरचना को सख्त बनाने की अनुमति देता है:

var a = [];
a[0] = a;
a[1] = 123;
console.log(JSON.stringify(JSON.decycle(a)));
// result: '[{"$ref":"$"},123]'.

आप retrocycleविधि के साथ मूल वस्तु को फिर से बना सकते हैं । इसलिए आपको उन्हें कड़ा करने के लिए वस्तुओं से चक्र हटाने की ज़रूरत नहीं है।

हालाँकि यह DOM Nodes के लिए काम नहीं करेगा (जो वास्तविक जीवन के उपयोग-मामलों में चक्र का विशिष्ट कारण हैं)। उदाहरण के लिए यह फेंक देगा:

var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a)));

मैंने उस समस्या को हल करने के लिए एक कांटा बनाया है (देखें मेरी साइकिलजेएस कांटा )। यह ठीक काम करना चाहिए:

var a = [document.body];
console.log(JSON.stringify(JSON.decycle(a, true)));

ध्यान दें कि मेरे कांटे JSON.decycle(variable)मूल के रूप में काम करते हैं और जब variableडोम नोड्स / तत्व होते हैं तो एक अपवाद फेंक देंगे ।

जब आप उपयोग JSON.decycle(variable, true)करते हैं तो आप इस तथ्य को स्वीकार करते हैं कि परिणाम प्रतिवर्ती नहीं होगा (रेट्रोसायकल डोम नोड्स को फिर से नहीं बनाएगा)। DOM तत्वों को कुछ हद तक पहचान योग्य होना चाहिए। उदाहरण के लिए यदि किसी divतत्व में एक आईडी है तो उसे एक स्ट्रिंग के साथ बदल दिया जाएगा "div#id-of-the-element"


2
जब मैं उनका उपयोग करता हूं तो उनका कोड और आपका दोनों मुझे "रेंजर्रर: अधिकतम कॉल स्टैक आकार से अधिक" देता है।
jcollum

मैं देख सकता हूँ कि क्या आप फिडल पर अपना कोड प्रदान करते हैं या Github पर कोई समस्या जोड़ते हैं: github.com/Eccenux/JSON-js/issues
Nux

यह वही है जिसे मैं देख रहा था। JSON.decycle(a, true)क्या होता है जब आप फंक्शन को रीसायकल करने के लिए एक पैरामीटर के रूप में सही होते हैं।
रुद्र

@ रुद्र सत्य stringifyNodesकांटे में विकल्प को सत्य बनाता है। यह divid = "some-id" को स्ट्रिंग से डंप करेगा div#some-id। आप कुछ समस्याओं से बचेंगे, लेकिन आप पूरी तरह से रेट्रो-चक्र में सक्षम नहीं होंगे।
नक्स

वहाँ npm पैकेज npmjs.com/package/json-js है , लेकिन यह थोड़ी देर के लिए अपडेट नहीं किया गया था
माइकल फ्रीजिम ऑक्ट

23

मैं @ isaacs-- से json- stringify -safe की जाँच करने की सलाह देता हूँ - इसका उपयोग NPM में किया जाता है।

BTW- यदि आप Node.js का उपयोग नहीं कर रहे हैं, तो आप स्रोत कोड के संबंधित भाग से लाइनों को 4-27 पर कॉपी और पेस्ट कर सकते हैं ।

स्थापित करने के लिए:

$ npm install json-stringify-safe --save

काम में लाना:

// Require the thing
var stringify = require('json-stringify-safe');

// Take some nasty circular object
var theBigNasty = {
  a: "foo",
  b: theBigNasty
};

// Then clean it up a little bit
var sanitized = JSON.parse(stringify(theBigNasty));

यह प्रदान करता है:

{
  a: 'foo',
  b: '[Circular]'
}

ध्यान दें कि, वैनिला JSON.stringify फ़ंक्शन के साथ @Rob W के रूप में उल्लेख किया गया है, आप "प्रतिकृति" फ़ंक्शन को दूसरे तर्क के रूप में पास करके स्वच्छता व्यवहार को भी अनुकूलित कर सकते हैं stringify()। यदि आप अपने आप को ऐसा करने के लिए एक सरल उदाहरण की आवश्यकता पाते हैं, तो मैंने सिर्फ एक कस्टम प्रतिकृति लिखी है जो यहां त्रुटियों, regexps और मानव-पठनीय तारों में कार्य करती है


13

जब आप सभी परिपत्र संदर्भों की कुंजी नहीं जानते हैं, तो इस समस्या के समाधान के लिए खोज करने वाले भविष्य के googlers के लिए , आप JSON.stringify फ़ंक्शन के चारों ओर एक आवरण का उपयोग करके परिपत्र संदर्भों को नियंत्रित कर सकते हैं। एक उदाहरण स्क्रिप्ट https://gist.github.com/4653128 पर देखें

समाधान अनिवार्य रूप से पहले से छपी हुई वस्तुओं के लिए एक सरणी में एक संदर्भ रखने के लिए उबलता है, और मान लौटने से पहले एक प्रतिकृति फ़ंक्शन में जाँच करता है। यह केवल परिपत्र संदर्भों को खारिज करने की तुलना में अधिक प्रतिबंधात्मक है, क्योंकि यह कभी भी दो बार किसी वस्तु को मुद्रित करने के नियम से अलग होता है, जिनमें से एक पक्ष को प्रभावित करता है कि परिपत्र संदर्भों से बचें।

उदाहरण आवरण:

function stringifyOnce(obj, replacer, indent){
    var printedObjects = [];
    var printedObjectKeys = [];

    function printOnceReplacer(key, value){
        var printedObjIndex = false;
        printedObjects.forEach(function(obj, index){
            if(obj===value){
                printedObjIndex = index;
            }
        });

        if(printedObjIndex && typeof(value)=="object"){
            return "(see " + value.constructor.name.toLowerCase() + " with key " + printedObjectKeys[printedObjIndex] + ")";
        }else{
            var qualifiedKey = key || "(empty key)";
            printedObjects.push(value);
            printedObjectKeys.push(qualifiedKey);
            if(replacer){
                return replacer(key, value);
            }else{
                return value;
            }
        }
    }
    return JSON.stringify(obj, printOnceReplacer, indent);
}

3
अच्छा कोड है। आपके पास एक मूर्खतापूर्ण त्रुटि है, हालांकि, आपको लिखते if(printedObjIndex)समय लिखना चाहिए if(printedObjIndex==false)क्योंकि indexयह भी हो सकता है 0जिसका अनुवाद falseतब तक किया जाए जब तक कि आप स्पष्ट रूप से अन्यथा राज्य न दें।
लड़का मोग्राबी

1
@guymograbi क्या आपका मतलब यह नहीं है ===? 0 == falseहै true, 0 === falseहै false। ; ^) लेकिन मैं printedObjIndexझूठे के लिए इनिशियलाइज़ नहीं करूँगा , क्योंकि तब आप जाँच कर सकते हैं undefinedताकि आप (अच्छी तरह से, ट्रिंडाज़ के) रूपकों को अजीब तरह से न मिलाएं।
रफिन

@ ब्रूफिन की अच्छी पकड़। हां जाहिर है, इस तरह की मूर्खतापूर्ण गलतियों को पकड़ने के लिए हमेशा कठिन समानता और जिश्ट का उपयोग करें।
पुरुष मोगरबी

4

प्रतिकृति के साथ JSON.stringify विधि का उपयोग करें। अधिक जानकारी के लिए इस दस्तावेज़ को पढ़ें। http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx

var obj = {
  a: "foo",
  b: obj
}

var replacement = {"b":undefined};

alert(JSON.stringify(obj,replacement));

चक्रीय संदर्भों के साथ प्रतिस्थापन सरणी को आबाद करने का एक तरीका है। आप यह पता लगाने के लिए टाइपो विधि का उपयोग कर सकते हैं कि क्या कोई संपत्ति 'ऑब्जेक्ट' (संदर्भ) और सर्कुलर संदर्भ को सत्यापित करने के लिए एक सटीक समानता जांच (===) है।


4
यह केवल IE में काम कर सकता है (इस तथ्य को देखते हुए कि MSDN Microsoft से प्रलेखन है, और Microsoft IE बनाता है)। फ़ायरफ़ॉक्स / क्रोम में, jsfiddle.net/ppmaW परिपत्र संदर्भ त्रुटि उत्पन्न करता है। जानकारी के लिए: var obj = {foo:obj}करता है नहीं एक परिपत्र संदर्भ बनाएगा। इसके बजाय, यह एक ऐसी वस्तु बनाता है जिसकी fooविशेषता पिछले मूल्य को संदर्भित करती है obj( undefinedयदि पहले परिभाषित नहीं है, तो इसकी वजह से घोषित किया गया है var obj)।
रॉब डब्ल्यू।

4

अगर

console.log(JSON.stringify(object));

में परिणाम

TypeError: चक्रीय वस्तु मान

फिर आप इस तरह प्रिंट करना चाहते हैं:

var output = '';
for (property in object) {
  output += property + ': ' + object[property]+'; ';
}
console.log(output);

21
हो सकता है क्योंकि यह केवल एक स्तर प्रिंट करता है?
एलेक्स टरपिन

बहुत आसान है क्योंकि मैं यह क्रोम में बॉक्स के ठीक बाहर काम के लिए यह upvoted। उत्कृष्ट
प्यार और शांति - जो कोडवेल

4
var a={b:"b"};
a.a=a;
JSON.stringify(preventCircularJson(a));

इसका मूल्यांकन करता है:

"{"b":"b","a":"CIRCULAR_REFERENCE_REMOVED"}"

समारोह के साथ:

/**
 * Traverses a javascript object, and deletes all circular values
 * @param source object to remove circular references from
 * @param censoredMessage optional: what to put instead of censored values
 * @param censorTheseItems should be kept null, used in recursion
 * @returns {undefined}
 */
function preventCircularJson(source, censoredMessage, censorTheseItems) {
    //init recursive value if this is the first call
    censorTheseItems = censorTheseItems || [source];
    //default if none is specified
    censoredMessage = censoredMessage || "CIRCULAR_REFERENCE_REMOVED";
    //values that have allready apeared will be placed here:
    var recursiveItems = {};
    //initaite a censored clone to return back
    var ret = {};
    //traverse the object:
    for (var key in source) {
        var value = source[key]
        if (typeof value == "object") {
            //re-examine all complex children again later:
            recursiveItems[key] = value;
        } else {
            //simple values copied as is
            ret[key] = value;
        }
    }
    //create list of values to censor:
    var censorChildItems = [];
    for (var key in recursiveItems) {
        var value = source[key];
        //all complex child objects should not apear again in children:
        censorChildItems.push(value);
    }
    //censor all circular values
    for (var key in recursiveItems) {
        var value = source[key];
        var censored = false;
        censorTheseItems.forEach(function (item) {
            if (item === value) {
                censored = true;
            }
        });
        if (censored) {
            //change circular values to this
            value = censoredMessage;
        } else {
            //recursion:
            value = preventCircularJson(value, censoredMessage, censorChildItems.concat(censorTheseItems));
        }
        ret[key] = value

    }

    return ret;
}

3

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैं एक एनपीएम पैकेज सुझाना चाहूंगा जिसे मैंने स्मार्ट-सर्कुलर कहा है , जो प्रस्तावित अन्य तरीकों से अलग तरह से काम करता है। यदि आप बड़ी और गहरी वस्तुओं का उपयोग कर रहे हैं तो यह विशेष रूप से उपयोगी है ।

कुछ विशेषताएं हैं:

  • अपनी पहली घटना के लिए पथ द्वारा वस्तु के अंदर परिपत्र संदर्भ या बस दोहराया संरचनाओं को बदलना (न केवल स्ट्रिंग [परिपत्र] );

  • चौड़ाई-प्रथम खोज में वृत्तिकों की तलाश करके, पैकेज सुनिश्चित करता है कि यह मार्ग जितना संभव हो उतना छोटा है, जो बहुत बड़ी और गहरी वस्तुओं के साथ काम करते समय महत्वपूर्ण है, जहां रास्ते कष्टप्रद लंबे और कठिन हो सकते हैं (कस्टम प्रतिस्थापन में) JSON.stringify एक DFS करता है);

  • व्यक्तिगत प्रतिस्थापन की अनुमति देता है, ऑब्जेक्ट के कम महत्वपूर्ण भागों को सरल या अनदेखा करना आसान है;

  • अंत में, मार्ग संदर्भित संदर्भित क्षेत्र तक पहुंचने के लिए आवश्यक तरीके से लिखे गए हैं, जो आपको डीबगिंग में मदद कर सकते हैं।


3

JSON.stringify () के लिए दूसरा तर्क भी आप कुंजी नाम है कि हर वस्तु यह आपके डेटा के भीतर का सामना करना पड़ता से संरक्षित किया जाना चाहिए की एक सरणी निर्दिष्ट करने के लिए अनुमति देता है। यह सभी उपयोग के मामलों के लिए काम नहीं कर सकता है, लेकिन बहुत सरल समाधान है।

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

var obj = {
    a: "foo",
    b: this
}

var json = JSON.stringify(obj, ['a']);
console.log(json);
// {"a":"foo"}

नोट: अजीब बात है, ओपी से ऑब्जेक्ट परिभाषा नवीनतम क्रोम या फ़ायरफ़ॉक्स में एक परिपत्र संदर्भ त्रुटि नहीं फेंकती है। इस जवाब में परिभाषा संशोधित किया गया था इतना है कि यह किया था एक त्रुटि फेंक देते हैं।



इस जवाब को स्वीकार किया जाना चाहिए
मैनिक डिप्रेशन

2

जिस तरह से JSON काम करता है (शायद अनुशंसित नहीं है, लेकिन सुपर सरल) के ओवरराइडिंग के उत्तर को अपडेट करने के लिए, इसका उपयोग न करें circular-json(यह पदावनत है)। इसके बजाय, उत्तराधिकारी का उपयोग करें, चपटा:

https://www.npmjs.com/package/flatted

@ User1541685 से ऊपर के पुराने उत्तर से उधार लिया गया, लेकिन नए के साथ बदल दिया गया:

npm i --save flatted

तो अपने जे एस फ़ाइल में

const CircularJSON = require('flatted');
const json = CircularJSON.stringify(obj);

1

मुझे जीथब पर सर्कुलर-जसन लाइब्रेरी मिली और इसने मेरी समस्या के लिए अच्छा काम किया।

कुछ अच्छी सुविधाएँ मुझे उपयोगी लगीं:

  • बहु-प्लेटफ़ॉर्म उपयोग का समर्थन करता है, लेकिन मैंने इसे केवल नोड.जेएस के साथ परीक्षण किया है।
  • API समान है, इसलिए आपको केवल JSON प्रतिस्थापन के रूप में शामिल करना और उसका उपयोग करना होगा।
  • इसकी स्वयं की पार्सिंग विधि है ताकि आप 'परिपत्र' क्रमबद्ध डेटा को वापस ऑब्जेक्ट में बदल सकें।

2
इस लाइब्रेरी ने मेरे लिए एक त्रुटि डाली ताकि मुझे दूसरे की तलाश करनी पड़े। ERROR टाइपError: toISOString ऑब्जेक्ट में String.toJSON (<अनाम) पर एक फ़ंक्शन नहीं है। <अनाम> ( localhost: 8100 / build / polyfills.js: 1: 3458 JSON.stringify (<अनाम>) ऑब्जेक्ट पर। stringifyRecursion [as stringify] ( लोकलहोस्ट: 8100 / बिल्ड / main.js: 258450: 15 )
मार्क

1
@MarkEllul मैंने 2015 में टिप्पणी लिखी है और अगर मुझे एक बेहतर विकल्प दिखाई देगा तो मैं इसे एक संपादन के साथ यहाँ पोस्ट करूँगा। मैं अभी भी दैनिक कार्यों में एक ही मुद्दे को कभी-कभी समाप्त करता हूं और मैं आमतौर पर एक उचित / सुरक्षित निरीक्षण के साथ अपने स्वयं के मैनुअल कार्यों को पुनरावर्ती तरीके से पसंद करता हूं। मेरा सुझाव है कि यदि आप अपरिचित हैं, तो आप कार्यात्मक प्रोग्रामिंग प्रथाओं की जांच कर सकते हैं, आमतौर पर, इस तरह के पुनरावर्ती संचालन को कम मुश्किल और अधिक विश्वसनीय माना जाता है।
जैकोपेन

"टोइज़िंगट्रींग एक फंक्शन नहीं है" को भी एक घटना को बढ़ाने और एक सरू परीक्षण में फिर से भेजने की कोशिश करना
डेविन जी रोड

1

मैं इस समस्या को इस तरह हल करता हूं:

var util = require('util');

// Our circular object
var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: 'Yo!'}}}}}}}};
obj.foo.bar = obj;

// Generate almost valid JS object definition code (typeof string)
var str = util.inspect(b, {depth: null});

// Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case)
str = str
    .replace(/<Buffer[ \w\.]+>/ig, '"buffer"')
    .replace(/\[Function]/ig, 'function(){}')
    .replace(/\[Circular]/ig, '"Circular"')
    .replace(/\{ \[Function: ([\w]+)]/ig, '{ $1: function $1 () {},')
    .replace(/\[Function: ([\w]+)]/ig, 'function $1(){}')
    .replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, '$1: new Date("$2"),')
    .replace(/(\S+): ,/ig, '$1: null,');

// Create function to eval stringifyed code
var foo = new Function('return ' + str + ';');

// And have fun
console.log(JSON.stringify(foo(), null, 4));

यह मेरे लिए बहुत काम आया लेकिन ऐसा लगता है जैसे कक्षाओं का प्रतिनिधित्व किया जा रहा था _class: ClassName { data: "here" }, इसलिए मैंने निम्नलिखित नियम जोड़ा .replace(/(\w+) {/g, '{ __ClassName__: "$1", ')। मेरे मामले में मैं यह देखने की कोशिश कर रहा था कि http अनुरोध वस्तु क्या दिखती है।
redbmk

1

मुझे पता है कि यह प्रश्न पुराना है और इसके बहुत सारे शानदार उत्तर हैं लेकिन मैं इसका उत्तर नए स्वाद के कारण देता हूं (es5 +)


1

यद्यपि यह पर्याप्त रूप से उत्तर दिया गया है, आप deleteसंचालक के उपयोग से पहले ही स्पष्ट रूप से संपत्ति को सख्ती से हटा सकते हैं ।

delete obj.b; 
const jsonObject = JSON.stringify(obj);

ऑपरेटर हटाएं

यह परिपत्र संदर्भों को हटाने के लिए जटिल तर्क को बनाने या बनाए रखने की आवश्यकता को हटा देगा।


1
function myStringify(obj, maxDeepLevel = 2) {
  if (obj === null) {
    return 'null';
  }
  if (obj === undefined) {
    return 'undefined';
  }
  if (maxDeepLevel < 0 || typeof obj !== 'object') {
    return obj.toString();
  }
  return Object
    .entries(obj)
    .map(x => x[0] + ': ' + myStringify(x[1], maxDeepLevel - 1))
    .join('\r\n');
}

0

इस तरह की वस्तुओं के साथ इस मुद्दे को हल करने के लिए एक अन्य समाधान यह है कि इस पुस्तकालय का उपयोग करना

https://github.com/ericmuyser/stringy

इसका सरल और आप कुछ सरल चरणों में हल कर सकते हैं।


0

अन्य उत्तरों के आधार पर मैं निम्नलिखित कोड के साथ समाप्त होता हूं। यह परिपत्र संदर्भों के साथ बहुत अच्छी तरह से काम करता है, कस्टम कन्स्ट्रक्टर के साथ ऑब्जेक्ट।

दी गई वस्तु से क्रमबद्ध होने के लिए,

  • ऑब्जेक्ट को ट्रेस करते समय आपके सामने आने वाली सभी ऑब्जेक्ट को कैश करें और उनमें से प्रत्येक को एक अद्वितीय हैशआईडी (एक ऑटो-इन्क्रिमिंग नंबर भी काम करता है) असाइन करें
  • एक बार एक सर्कुलर रेफरेंस मिलने के बाद उस ऑब्जेक्ट को नए ऑब्जेक्ट में सर्कुलर के रूप में मार्क किया जाता है और ऑरिजनल ऑब्जेक्ट के हैश को एक विशेषता के रूप में स्टोर किया जाता है।

जीथब लिंक - डिसाइकल्डजसन

DJSHelper = {};
DJSHelper.Cache = [];
DJSHelper.currentHashID = 0;
DJSHelper.ReviveCache = [];

// DOES NOT SERIALIZE FUNCTION
function DJSNode(name, object, isRoot){
    this.name = name;
    // [ATTRIBUTES] contains the primitive fields of the Node
    this.attributes = {};

    // [CHILDREN] contains the Object/Typed fields of the Node
    // All [CHILDREN] must be of type [DJSNode]
    this.children = []; //Array of DJSNodes only

    // If [IS-ROOT] is true reset the Cache and currentHashId
    // before encoding
    isRoot = typeof isRoot === 'undefined'? true:isRoot;
    this.isRoot = isRoot;
    if(isRoot){
        DJSHelper.Cache = [];
        DJSHelper.currentHashID = 0;

        // CACHE THE ROOT
        object.hashID = DJSHelper.currentHashID++;
        DJSHelper.Cache.push(object);
    }

    for(var a in object){
        if(object.hasOwnProperty(a)){
            var val = object[a];

            if (typeof val === 'object') {
                // IF OBJECT OR NULL REF.

                /***************************************************************************/
                // DO NOT REMOVE THE [FALSE] AS THAT WOULD RESET THE [DJSHELPER.CACHE]
                // AND THE RESULT WOULD BE STACK OVERFLOW
                /***************************************************************************/
                if(val !== null) {
                    if (DJSHelper.Cache.indexOf(val) === -1) {
                        // VAL NOT IN CACHE
                        // ADD THE VAL TO CACHE FIRST -> BEFORE DOING RECURSION
                        val.hashID = DJSHelper.currentHashID++;
                        //console.log("Assigned", val.hashID, "to", a);
                        DJSHelper.Cache.push(val);

                        if (!(val instanceof Array)) {
                            // VAL NOT AN [ARRAY]
                            try {
                                this.children.push(new DJSNode(a, val, false));
                            } catch (err) {
                                console.log(err.message, a);
                                throw err;
                            }
                        } else {
                            // VAL IS AN [ARRAY]
                            var node = new DJSNode(a, {
                                array: true,
                                hashID: val.hashID // HashID of array
                            }, false);
                            val.forEach(function (elem, index) {
                                node.children.push(new DJSNode("elem", {val: elem}, false));
                            });
                            this.children.push(node);
                        }
                    } else {
                        // VAL IN CACHE
                        // ADD A CYCLIC NODE WITH HASH-ID
                        this.children.push(new DJSNode(a, {
                            cyclic: true,
                            hashID: val.hashID
                        }, false));
                    }
                }else{
                    // PUT NULL AS AN ATTRIBUTE
                    this.attributes[a] = 'null';
                }
            } else if (typeof val !== 'function') {
                // MUST BE A PRIMITIVE
                // ADD IT AS AN ATTRIBUTE
                this.attributes[a] = val;
            }
        }
    }

    if(isRoot){
        DJSHelper.Cache = null;
    }
    this.constructorName = object.constructor.name;
}
DJSNode.Revive = function (xmlNode, isRoot) {
    // Default value of [isRoot] is True
    isRoot = typeof isRoot === 'undefined'?true: isRoot;
    var root;
    if(isRoot){
        DJSHelper.ReviveCache = []; //Garbage Collect
    }
    if(window[xmlNode.constructorName].toString().indexOf('[native code]') > -1 ) {
        // yep, native in the browser
        if(xmlNode.constructorName == 'Object'){
            root = {};
        }else{
            return null;
        }
    }else {
        eval('root = new ' + xmlNode.constructorName + "()");
    }

    //CACHE ROOT INTO REVIVE-CACHE
    DJSHelper.ReviveCache[xmlNode.attributes.hashID] = root;

    for(var k in xmlNode.attributes){
        // PRIMITIVE OR NULL REF FIELDS
        if(xmlNode.attributes.hasOwnProperty(k)) {
            var a = xmlNode.attributes[k];
            if(a == 'null'){
                root[k] = null;
            }else {
                root[k] = a;
            }
        }
    }

    xmlNode.children.forEach(function (value) {
        // Each children is an [DJSNode]
        // [Array]s are stored as [DJSNode] with an positive Array attribute
        // So is value

        if(value.attributes.array){
            // ITS AN [ARRAY]
            root[value.name] = [];
            value.children.forEach(function (elem) {
                root[value.name].push(elem.attributes.val);
            });
            //console.log("Caching", value.attributes.hashID);
            DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name];
        }else if(!value.attributes.cyclic){
            // ITS AN [OBJECT]
            root[value.name] = DJSNode.Revive(value, false);
            //console.log("Caching", value.attributes.hashID);
            DJSHelper.ReviveCache[value.attributes.hashID] = root[value.name];
        }
    });

    // [SEPARATE ITERATION] TO MAKE SURE ALL POSSIBLE
    // [CYCLIC] REFERENCES ARE CACHED PROPERLY
    xmlNode.children.forEach(function (value) {
        // Each children is an [DJSNode]
        // [Array]s are stored as [DJSNode] with an positive Array attribute
        // So is value

        if(value.attributes.cyclic){
            // ITS AND [CYCLIC] REFERENCE
            root[value.name] = DJSHelper.ReviveCache[value.attributes.hashID];
        }
    });

    if(isRoot){
        DJSHelper.ReviveCache = null; //Garbage Collect
    }
    return root;
};

DecycledJSON = {};
DecycledJSON.stringify = function (obj) {
    return JSON.stringify(new DJSNode("root", obj));
};
DecycledJSON.parse = function (json, replacerObject) {
    // use the replacerObject to get the null values
    return DJSNode.Revive(JSON.parse(json));
};
DJS = DecycledJSON;

उदाहरण उपयोग 1:

var obj = {
    id:201,
    box: {
        owner: null,
        key: 'storm'
    },
    lines:[
        'item1',
        23
    ]
};

console.log(obj); // ORIGINAL

// SERIALIZE AND THEN PARSE
var jsonObj = DJS.stringify(obj);
console.log(DJS.parse(jsonObj));

उदाहरण उपयोग 2:

// PERSON OBJECT

function Person() {
    this.name = null;
    this.child = null;
    this.dad = null;
    this.mom = null;
}
var Dad = new Person();
Dad.name = 'John';
var Mom = new Person();
Mom.name = 'Sarah';
var Child = new Person();
Child.name = 'Kiddo';

Dad.child = Mom.child = Child;
Child.dad = Dad;
Child.mom = Mom;

console.log(Child); // ORIGINAL

// SERIALIZE AND THEN PARSE
var jsonChild = DJS.stringify(Child);
console.log(DJS.parse(jsonChild));

0

इसे इस्तेमाल करे:

var obj = {
    a: "foo",
    b: obj
};

var circular_replacer = (value) => {
    var seen = [];
    if (value != null && typeof value == "object") {
        if (seen.indexOf(value) >= 0) return;
        seen.push(value);
    }
    return value;
};

obj = circular_replacer(obj);

क्या seen.push(value)= -D के बाद कोड की कुछ और पंक्तियाँ नहीं होनी चाहिए ? जैसेfor (var key in value) {value[key] = circular_replacer(value[key]);}
क्लेसन

कोड-केवल उत्तर हतोत्साहित किए जाते हैं। कृपया संपादित करें पर क्लिक करें और कुछ शब्दों को जोड़कर बताएं कि आपका कोड प्रश्न को कैसे संबोधित करता है, या शायद समझाएं कि आपका उत्तर पिछले उत्तर / उत्तरों से कैसे भिन्न है। समीक्षा से
निक

0

मेरे समाधान में, यदि आप एक चक्र में दौड़ते हैं, तो यह सिर्फ "चक्र" (या कुछ भी नहीं) नहीं कहता है, यह फू जैसा कुछ कहता है: ऑब्जेक्ट को # 42 से ऊपर देखें, और यह देखने के लिए कि कहां से आप को इंगित और स्क्रॉल कर सकते हैं। ऑब्जेक्ट # 42 के लिए (प्रत्येक ऑब्जेक्ट, जब यह शुरू होता है, ऑब्जेक्ट कहता है # xxx कुछ पूर्णांक xxx के साथ)

स्निपेट:

(function(){
	"use strict";
	var ignore = [Boolean, Date, Number, RegExp, String];
	function primitive(item){
		if (typeof item === 'object'){
			if (item === null) { return true; }
			for (var i=0; i<ignore.length; i++){
				if (item instanceof ignore[i]) { return true; }
			}
			return false;
		} else {
			return true;
		}
	}
	function infant(value){
		return Array.isArray(value) ? [] : {};
	}
	JSON.decycleIntoForest = function decycleIntoForest(object, replacer) {
		if (typeof replacer !== 'function'){
			replacer = function(x){ return x; }
		}
		object = replacer(object);
		if (primitive(object)) return object;
		var objects = [object];
		var forest  = [infant(object)];
		var bucket  = new WeakMap(); // bucket = inverse of objects 
		bucket.set(object, 0);       // i.e., map object to index in array
		function addToBucket(obj){
			var result = objects.length;
			objects.push(obj);
			bucket.set(obj, result);
			return result;
		}
		function isInBucket(obj){
			return bucket.has(obj);
			// objects[bucket.get(obj)] === obj, iff true is returned
		}
		function processNode(source, target){
			Object.keys(source).forEach(function(key){
				var value = replacer(source[key]);
				if (primitive(value)){
					target[key] = {value: value};
				} else {
					var ptr;
					if (isInBucket(value)){
						ptr = bucket.get(value);
					} else {
						ptr = addToBucket(value);
						var newTree = infant(value);
						forest.push(newTree);
						processNode(value, newTree);
					}
					target[key] = {pointer: ptr};
				}
			});
		}
		processNode(object, forest[0]);
		return forest;
	};
})();
the = document.getElementById('the');
function consoleLog(toBeLogged){
  the.textContent = the.textContent + '\n' + toBeLogged;
}
function show(root){
	var cycleFree = JSON.decycleIntoForest(root);
	var shown = cycleFree.map(function(tree, idx){ return false; });
	var indentIncrement = 4;
	function showItem(nodeSlot, indent, label){
	  leadingSpaces = ' '.repeat(indent);
      leadingSpacesPlus = ' '.repeat(indent + indentIncrement);
	  if (shown[nodeSlot]){
	  consoleLog(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')');
        } else {
		  consoleLog(leadingSpaces + label + ' object#' + nodeSlot);
		  var tree = cycleFree[nodeSlot];
		  shown[nodeSlot] = true;
		  Object.keys(tree).forEach(function(key){
			var entry = tree[key];
			if ('value' in entry){
			  consoleLog(leadingSpacesPlus + key + ": " + entry.value);
                } else {
					if ('pointer' in entry){
						showItem(entry.pointer, indent+indentIncrement, key);
                    }
                }
			});
        }
    }
	showItem(0, 0, 'root');
}
cities4d = {
	Europe:{
		north:[
			{name:"Stockholm", population:1000000, temp:6},
			{name:"Helsinki", population:650000, temp:7.6}
		],
		south:[
			{name:"Madrid", population:3200000, temp:15},
			{name:"Rome", population:4300000, temp:15}
		]
	},
	America:{
		north:[
			{name:"San Francisco", population:900000, temp:14},
			{name:"Quebec", population:530000, temp:4}
		],
		south:[
			{name:"Rio de Janeiro", population:7500000, temp:24},
			{name:"Santiago", population:6300000, temp:14}
		]
	},
	Asia:{
		north:[
			{name:"Moscow", population:13200000, temp:6}
		]
	}
};
cities4d.Europe.north[0].alsoStartsWithS = cities4d.America.north[0];
cities4d.Europe.north[0].smaller = cities4d.Europe.north[1];
cities4d.Europe.south[1].sameLanguage = cities4d.America.south[1];
cities4d.Asia.ptrToRoot = cities4d;
show(cities4d)
<pre id="the"></pre>

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.