सीरियलाइज़िंग ऑब्जेक्ट जिसमें चक्रीय ऑब्जेक्ट वैल्यू होती है


151

मेरे पास एक ऑब्जेक्ट (पार्स ट्री) है जिसमें बाल नोड्स हैं जो अन्य नोड्स के संदर्भ हैं।

मैं इस ऑब्जेक्ट को क्रमबद्ध करना चाहूंगा, उपयोग कर JSON.stringify()रहा हूं, लेकिन मुझे मिलता है

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

मेरे द्वारा बताए गए निर्माणों के कारण।

मैं इसके आसपास कैसे काम कर सकता था? मुझे इससे कोई फर्क नहीं पड़ता कि क्या अन्य नोड्स के इन संदर्भों का प्रतिनिधित्व या अनुक्रमित ऑब्जेक्ट में किया गया है या नहीं।

दूसरी ओर, जब वे बनाए जा रहे हैं तो इन गुणों को हटाने से थकाऊ लगता है और मैं पार्सर (नार्सिसस) में बदलाव नहीं करना चाहता।


1
हम कुछ कोड के बिना आपकी मदद नहीं कर सकते। कृपया अपनी वस्तु और / या JSON आउटपुट के प्रासंगिक बिट्स को JS के साथ पोस्ट करें जिसे आप इसे क्रमबद्ध करने के लिए उपयोग करते हैं।
Bojangles

1
क्या आप उन गुणों में कुछ उपसर्ग जोड़ने में सक्षम हैं जो आंतरिक संदर्भ हैं?
wheresrhys

@ लोइक यह cycle.jsएक जवाब के रूप में डगलस क्रॉकफोर्ड के लिए मूल्यवान होगा , क्योंकि यह बहुत सारे मामलों के लिए सबसे उपयुक्त समाधान है। आपके लिए उस उत्तर को पोस्ट करना उचित लगता है, क्योंकि आप इसे संदर्भित करने वाले पहले व्यक्ति हैं (नीचे अपनी टिप्पणी में)। यदि आप इसे स्वयं एक उत्तर के रूप में पोस्ट करने का मन नहीं करते हैं, तो मैं अंततः ऐसा करूंगा।
जेरेमी बैंक्स


1
काश JSON होशियार, या इसे हल करने का एक आसान तरीका होगा। समाधान बहुत सरल (!) डीबगिंग प्रयोजनों के लिए परेशानी हैं।
ब्लू सिप

जवाबों:


220

पहले से क्रमबद्ध वस्तुओं को बाहर करने के लिए stringify, दुसरे पैरामीटर के दुहराव का उपयोग करें :

var seen = [];

JSON.stringify(obj, function(key, val) {
   if (val != null && typeof val == "object") {
        if (seen.indexOf(val) >= 0) {
            return;
        }
        seen.push(val);
    }
    return val;
});

http://jsfiddle.net/mH6cJ/38/

जैसा कि अन्य टिप्पणियों में सही ढंग से बताया गया है, यह कोड हर "देखी गई" वस्तु को हटाता है, न केवल "पुनरावर्ती" वाले।

उदाहरण के लिए, इसके लिए:

a = {x:1};
obj = [a, a];

परिणाम गलत होगा। यदि आपकी संरचना इस तरह की है, तो आप क्रॉकफोर्ड के साइकल या इस (सरल) फ़ंक्शन का उपयोग करना चाह सकते हैं, जो सिर्फ नल के साथ पुनरावर्ती संदर्भों को बदलता है:

function decycle(obj, stack = []) {
    if (!obj || typeof obj !== 'object')
        return obj;
    
    if (stack.includes(obj))
        return null;

    let s = stack.concat([obj]);

    return Array.isArray(obj)
        ? obj.map(x => decycle(x, s))
        : Object.fromEntries(
            Object.entries(obj)
                .map(([k, v]) => [k, decycle(v, s)]));
}

//

let a = {b: [1, 2, 3]}
a.b.push(a);

console.log(JSON.stringify(decycle(a)))


3
आआह अच्छा! धन्यवाद, मैं यह कोशिश करने जा रहा हूं। मुझे डगलस क्रॉकफ़ोर्ड ( github.com/douglascrockford/JSON-js/blob/master/cycle.js ) द्वारा बनाया गया एक समाधान मिला , लेकिन जैसा कि मैं इसके साथ जाने वाले लाइसेंस के बारे में अनिश्चित हूं, आपके द्वारा वर्णित आसान समाधान सही होगा!
Loic Duros

3
@LoicDuros लाइसेंस "सार्वजनिक डोमेन" है। मतलब, आप इसके साथ कुछ भी कर सकते हैं।
एटलेस गोरल

1
यह कोड साइक्लिंग लूप का उत्पादन करता है, उपयोग करने से सावधान रहें, बहुत ही संभावित आपके ऐप को क्रैश करता है। सही अर्धविराम की जरूरत है और घटना वस्तुओं पर प्रयोग करने योग्य नहीं है!
ऑल सेन

3
यह चक्रीय संदर्भों से अधिक को हटा देता है - यह बस एक बार से अधिक दिखाई देने वाली किसी भी चीज़ को हटा देता है। जब तक वह वस्तु जो पहले से सीरियलाइज़ हो चुकी है, नई वस्तु का "पैरेंट" है, तो आपको उसे डिलीट नहीं करना चाहिए
Gio

1
अच्छा उत्तर! मैंने इसे थोड़ा संशोधित किया, फ़ंक्शन को एक पुनरावर्ती फ़ंक्शन में बदल दिया, ताकि बच्चे-वस्तुओं को क्लोन किया जाए जिस तरह से माता-पिता की वस्तुओं को क्लोन किया जाता है।
होल्डऑफ ह्यूंगर

2

मैंने एक GitHub Gist बनाया है जो चक्रीय संरचनाओं का पता लगाने में सक्षम है और उन्हें भी डी-एन्कोड करता है: https://gist.github.com/Hoff97/9842228

केवल JSONE.stringify / JSONE.parse का उपयोग करने के लिए। यह डे- और फ़ंक्शन को भी डीकोड करता है। यदि आप इसे अक्षम करना चाहते हैं तो बस 32-48 और 61-85 की लाइनें हटा दें।

var strg = JSONE.stringify(cyclicObject);
var cycObject = JSONE.parse(strg);

आप यहाँ एक उदाहरण पा सकते हैं:

http://jsfiddle.net/hoff97/7UYd4/


2

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

एक विशेषता जो उतनी अच्छी नहीं है, जितनी कि जानी जाती JSON.stringify()है console.table()। बस कॉल करें console.table(whatever);, और यह कंसोल को सारणीबद्ध स्वरूप में चर में लॉग करेगा, जिससे चर की सामग्री को भ्रमित करना आसान और सुविधाजनक हो जाएगा।


1

ज्यादा सुरक्षित और यह दिखाता है कि एक चक्र वस्तु कहां थी।

<script>
var jsonify=function(o){
    var seen=[];
    var jso=JSON.stringify(o, function(k,v){
        if (typeof v =='object') {
            if ( !seen.indexOf(v) ) { return '__cycle__'; }
            seen.push(v);
        } return v;
    });
    return jso;
};
var obj={
    g:{
        d:[2,5],
        j:2
    },
    e:10
};
obj.someloopshere = [
    obj.g,
    obj,
    { a: [ obj.e, obj ] }
];
console.log('jsonify=',jsonify(obj));
</script>

पैदा करता है

jsonify = {"g":{"d":[2,5],"j":2},"e":10,"someloopshere":[{"d":[2,5],"j":2},"__cycle__",{"a":[10,"__cycle__"]}]}

लेकिन इस कोड के साथ अभी भी एक मुद्दा है अगर कोई व्यक्ति किसी वस्तु का निर्माण करेगा obj.b=this'यदि कोई जानता है कि किसी गलत तरीके से दिए गए बहुत लंबे बछड़ों को कैसे रोका thisजाए तो यहां देखना अच्छा होगा
Ol Sen

2
यह होना चाहिएseen.indexOf(v) != -1

1

मैं एक गितुब परियोजना बनाता हूं जो चक्रीय वस्तु को अनुक्रमित कर सकती है और वर्ग को पुनर्स्थापित कर सकती है यदि आप इसे धारावाहिक में स्ट्रींग जैसी विशेषता में सहेजते हैं

var d={}
var a = {b:25,c:6,enfant:d};
d.papa=a;
var b = serializeObjet(a);
assert.equal(  b, "{0:{b:25,c:6,enfant:'tab[1]'},1:{papa:'tab[0]'}}" );
var retCaseDep = parseChaine(b)
assert.equal(  retCaseDep.b, 25 );
assert.equal(  retCaseDep.enfant.papa, retCaseDep );

https://github.com/bormat/serializeStringifyParseCyclicObject

संपादित करें: मैंने NPM https://github.com/bormat/borto_circular_serialize के लिए अपनी स्क्रिप्ट को रूपांतरित किया है और मेरे पास फ्रेंच से अंग्रेजी में फ़ंक्शन नाम हैं।


यह उदाहरण जिस्ट के लायक नहीं है। Gist में त्रुटियाँ हैं।
अर्नस्ट अर्नस्ट

अच्छा विचार है - लेकिन एक बार इसे तैयार कर लें :-) यदि आप इसे npm में वितरित करेंगे, तो शायद आप इसके लिए भी टाइपिंग विकसित करेंगे, यह संभवतः काफी लोकप्रिय हो गया है।
पीटर - मोनिका

1

यहाँ चक्रीय संदर्भों के साथ डेटा संरचना का एक उदाहरण दिया गया है: toolshedCY

function makeToolshed(){
    var nut = {name: 'nut'}, bolt = {name: 'bolt'};
    nut.needs = bolt; bolt.needs = nut;
    return { nut: nut, bolt: bolt };
}

जब आप चक्रीय संदर्भों को KEEP करना चाहते हैं (जब आप उन्हें डिस्क्राइब करते हैं ("nuking" के बजाय उन्हें पुनर्स्थापित करें), तो आपके पास 2 विकल्प हैं, जिनकी मैं यहाँ तुलना करूँगा। पहला है डगलस क्रॉफोर्ड का चक्र । दूसरा, मेरा साइबेरिया पैकेज है। दोनों पहले "डिक्रिप्शन" ऑब्जेक्ट द्वारा काम करते हैं, अर्थात, किसी अन्य ऑब्जेक्ट का निर्माण (बिना किसी चक्रीय संदर्भ के) "एक ही जानकारी युक्त"।

मिस्टर क्रॉकफोर्ड पहले जाता है:

JSON.decycle(makeToolshed())

JSON_decycleMakeToolshed

जैसा कि आप देखते हैं, JSON की नेस्टेड संरचना को बरकरार रखा गया है, लेकिन एक नई चीज है, जो विशेष $refसंपत्ति वाली वस्तुएं हैं। आइए देखें कि यह कैसे काम करता है।

root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]

डॉलर का संकेत जड़ के लिए खड़ा है। .boltहोने $refहमें बताता है कि .boltएक "पहले से ही देखा" वस्तु है, और कहा कि विशेष संपत्ति का मूल्य (यहाँ, स्ट्रिंग $ [ "अखरोट"] [ "की जरूरत है"]) हमें जहां, पहले देखने के लिए कहता है ===ऊपर। इसी तरह दूसरा $refऔर ===ऊपर दूसरा ।

यदि क्लोनिंग काम करती है तो यह देखने के लिए एक उपयुक्त गहरी समानता परीक्षण (अर्थात इस प्रश्न केdeepGraphEqual स्वीकृत उत्तर से एंडर्स कसेग के कार्य ) का उपयोग करें।

root = makeToolshed();
clone = JSON.retrocycle(JSON.decycle(root));
deepGraphEqual(root, clone) // true
serialized = JSON.stringify(JSON.decycle(root));
clone2 = JSON.retrocycle(JSON.parse(serialized));
deepGraphEqual(root, clone2); // true

अब, साइबेरिया:

JSON.Siberia.forestify(makeToolshed())

JSON_Siberia_forestify_makeToolshed

साइबेरिया "क्लासिक" JSON की नकल करने की कोशिश नहीं करता है, कोई नेस्टेड संरचना नहीं है। ऑब्जेक्ट ग्राफ को "सपाट" तरीके से वर्णित किया गया है। ऑब्जेक्ट ग्राफ के प्रत्येक नोड को एक फ्लैट ट्री (पूर्णांक-केवल मानों के साथ सादे कुंजी मूल्य जोड़ी) में बदल दिया जाता है, जो .forest.एट इंडेक्स में एक प्रविष्टि है, हम रूट ऑब्जेक्ट को उच्च सूचकांकों में पाते हैं, हम अन्य नोड्स को खोजते हैं ऑब्जेक्ट ग्राफ, और नकारात्मक मान (जंगल के कुछ पेड़ की कुछ कुंजी) atomsसरणी को इंगित करते हैं , (जो प्रकार सरणी के माध्यम से टाइप किया जाता है, लेकिन हम यहां टाइपिंग विवरण छोड़ देंगे)। सभी टर्मिनल नोड्स परमाणु तालिका में हैं, सभी गैर-टर्मिनल नोड्स वन तालिका में हैं, और आप तुरंत देख सकते हैं कि ऑब्जेक्ट ग्राफ में कितने नोड हैं, अर्थात् forest.length। चलो परीक्षण अगर यह काम करता है:

root = makeToolshed();
clone = JSON.Siberia.unforestify(JSON.Siberia.forestify(root));
deepGraphEqual(root, clone); // true
serialized = JSON.Siberia.stringify(JSON.Siberia.forestify(root));
clone2 = JSON.Siberia.unforestify(JSON.Siberia.unstringify(serialized));
deepGraphEqual(root, clone2); // true

तुलना

बाद में अनुभाग जोड़ देगा।


0
function stringifyObject ( obj ) {
  if ( _.isArray( obj ) || !_.isObject( obj ) ) {
    return obj.toString()
  }
  var seen = [];
  return JSON.stringify(
    obj,
    function( key, val ) {
      if (val != null && typeof val == "object") {
        if ( seen.indexOf( val ) >= 0 )
          return
          seen.push( val )
          }
      return val
    }
  );
}

एक पूर्व शर्त गायब थी, अन्यथा सरणी ऑब्जेक्ट्स में पूर्णांक मानों को छोटा कर दिया जाता है, अर्थात [[०.11.११/२०१२ १२:३०, १३ ९ ५]] १० ९ ५ घटकर ० ९ ५ हो जाता है।


RefrenceError प्राप्त करना: चर नहीं पा सकते: _
amit pandya

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