2012-01-19 19 views
36

MDN documentation for JSON.stringify के अनुसार:निर्धारित करने के लिए कैसे एक JSON ऑब्जेक्ट संशोधित नहीं किया गया है?

गैर सरणी वस्तुओं के गुण किसी विशेष क्रम में stringified होने की गारंटी नहीं कर रहे हैं। के भीतर स्ट्रिंग के भीतर एक ही ऑब्जेक्ट के ऑर्डर करने पर भरोसा न करें।

मुझे यह निर्धारित करने की उम्मीद थी कि ऑब्जेक्ट के एक स्ट्रिंग संस्करण को कैश करके कोई ऑब्जेक्ट बदल गया है, फिर उसे ऑब्जेक्ट के बाद के स्ट्रिंगिफाइड संस्करण से तुलना कर रहा है। ऑब्जेक्ट के माध्यम से पुनरावर्ती रूप से पुनरावृत्ति करने और तुलना करने से यह बहुत आसान लग रहा था। समस्या यह है कि JSON.stringify फ़ंक्शन निर्धारित नहीं है, जब मैं एक ही ऑब्जेक्ट को स्ट्रिंग करता हूं तो तकनीकी रूप से एक अलग स्ट्रिंग प्राप्त कर सकता हूं।

मेरे पास अन्य विकल्प क्या हैं? या क्या ऑब्जेक्ट समानता निर्धारित करने के लिए मुझे एक बुरा तुलना फ़ंक्शन लिखना है?

+1

आप [इस 'JSON' कार्यान्वयन] (https://github.com/douglascrockford/JSON-js) पर एक नजर है और यह इतना है कि कुंजी हल कर रहे हैं को संशोधित कर सकता है । –

+3

शायद थोड़ा असंबंधित है, लेकिन ध्यान दें कि एक * पूरी तरह से * निर्धारक स्ट्रिंगिंग फ़ंक्शन संभव नहीं है: 'JSON.stringify ({get a() {return Math.random()}}; '। – pimvdb

+0

यह अधिक हो सकता है, लेकिन आप किसी ऑब्जेक्ट में 'चेंज' ईवेंट सेट करने के लिए बैकबोन जेएस का उपयोग कर सकते हैं और यदि यह बदलता है तो यह आपके इच्छित कार्य को बंद कर देगा। यह पूरी लाइब्रेरी का एक छोटा टुकड़ा है, लेकिन यह वही हो सकता है जो आप खोज रहे हैं। – Seth

उत्तर

9

मुझे पूरा यकीन है कि यह अलग-अलग जावास्क्रिप्ट इंजन आंतरिक रूप से ऑब्जेक्ट गुणों का ट्रैक रखने के कारण है। उदाहरण के लिए इसे लें:

var obj = { 
"1" : "test", 
"0" : "test 2" 
}; 

for(var key in obj) { 
    console.log(key); 
} 

यह 1, 0 में लॉग इन करेगा। फ़ायरफ़ॉक्स, लेकिन V8 (क्रोम और नोडजेएस) में 0, 1। इसलिए यदि आपको निर्धारक होने की आवश्यकता है, तो आपको शायद प्रत्येक सर स्टोर के माध्यम से इसे सरणी में फिर से भरना होगा, सरणी को सॉर्ट करें और फिर उस सरणी के माध्यम से लूपिंग करके प्रत्येक प्रॉपर्टी को अलग से स्ट्रिंग करें।

0

कुछ चीजें जिन्हें आप विचार करना चाहते हैं: किसी वस्तु के लिए अलग होने का क्या अर्थ है? क्या आप देख रहे हैं कि उस ऑब्जेक्ट पर कोई संपत्ति बदल गई है या नहीं? इन परिवर्तनों के बारे में 'जानने' में रुचि रखने वाले कौन हैं? क्या आप तुरंत जानना चाहते हैं कि कोई वस्तु संपत्ति बदल गई है या नहीं?

आप उस ऑब्जेक्ट को 'अवलोकन योग्य' गुणों पर गुण बना सकते हैं और जब वह संपत्ति बदलती है तो आप किसी ईवेंट को आग लगा सकते हैं और जो भी दिलचस्पी लेता है, वह संपत्ति परिवर्तनों की सदस्यता ले सकता है। इस तरह आप तुरंत जानते हैं कि क्या बदल गया है और आप जो भी जानकारी चाहते हैं वह कर सकते हैं। Knockout.js इस दृष्टिकोण का उपयोग करें। इस तरह आपको 'बुरा' ऑब्जेक्ट तुलना का उपयोग नहीं करना है

5

यहां लिखा गया एक निर्धारक JSON.stringify() का कार्यान्वयन है (Underscore.js का उपयोग करता है)। यह क्रमबद्ध कुंजी-मूल्य जोड़े (Arrays के रूप में) में क्रमशः (गैर-सरणी) वस्तुओं को परिवर्तित करता है, फिर उनको स्ट्रिंग करता है। मूल कोडरवाल पोस्ट here

Stringify:

function stringify(obj) { 
    function flatten(obj) { 
    if (_.isObject(obj)) { 
     return _.sortBy(_.map(
      _.pairs(obj), 
      function(p) { return [p[0], flatten(p[1])]; } 
     ), 
     function(p) { return p[0]; } 
    ); 
    } 
    return obj; 
    } 
    return JSON.stringify(flatten(obj)); 
} 

पार्स:

function parse(str) { 
    function inflate(obj, pairs) { 
    _.each(pairs, function(p) { 
     obj[p[0]] = _.isArray(p[1]) ? 
     inflate({}, p[1]) : 
     p[1]; 
    }); 
    return obj; 
    } 
    return inflate({}, JSON.parse(str)); 
} 
+2

सावधान रहें, हालांकि, उपरोक्त स्ट्रिंगफ़ाई का उपयोग करके, 'स्ट्रिंग ({0: "a"}) == स्ट्रिंग ([ "ए"]) ', जो थोड़ा दोषपूर्ण है। –

+0

अच्छा बिंदु, @ पीटरवी। मॉर्च। मैं विवरण में एक नोट जोड़ूंगा कि इन कार्यों का उपयोग उचित, गैर-सरणी वस्तुओं के साथ किया जाना चाहिए। –

+2

ध्यान रखें, यह शीर्ष स्तर पर केवल सरणी नहीं है, लेकिन मनमानी गहराई पर कोई भी सरणी है। जैसे ध्यान दें कि: 'स्ट्रिफ़ाई ({a: {0: "a"}}) == स्ट्रिंग ({a: ["a"]}) '। इसलिए यदि डेटा संरचना कहीं भी सरणी का उपयोग करती है, तो मैं एक गैर-सरणी केवल संरचना का निर्माण करने में सक्षम हूं जो समान 'स्ट्रिंगफ़ी' स्ट्रिंग देता है। –

3

इन दिनों मैं एक वस्तु stringify को नियतात्मक तरीके के साथ खेल रहा है और मैं JSON करने का आदेश दिया वस्तु stringify लिखा है, कि उपरोक्त उल्लेखनीय दुविधा हल करता है: http://stamat.wordpress.com/javascript-object-ordered-property-stringify/

इसके अलावा मैं कस्टम हैश तालिका कार्यान्वयन के साथ खेल रहा था जो विषय से संबंधित है: http://stamat.wordpress.com/javascript-quickly-find-very-large-objects-in-a-large-array/

//SORT WITH STRINGIFICATION 

var orderedStringify = function(o, fn) { 
    var props = []; 
    var res = '{'; 
    for(var i in o) { 
     props.push(i); 
    } 
    props = props.sort(fn); 

    for(var i = 0; i < props.length; i++) { 
     var val = o[props[i]]; 
     var type = types[whatis(val)]; 
     if(type === 3) { 
      val = orderedStringify(val, fn); 
     } else if(type === 2) { 
      val = arrayStringify(val, fn); 
     } else if(type === 1) { 
      val = '"'+val+'"'; 
     } 

     if(type !== 4) 
      res += '"'+props[i]+'":'+ val+','; 
    } 

    return res.substring(res, res.lastIndexOf(','))+'}'; 
}; 

//orderedStringify for array containing objects 
var arrayStringify = function(a, fn) { 
    var res = '['; 
    for(var i = 0; i < a.length; i++) { 
     var val = a[i]; 
     var type = types[whatis(val)]; 
     if(type === 3) { 
      val = orderedStringify(val, fn); 
     } else if(type === 2) { 
      val = arrayStringify(val); 
     } else if(type === 1) { 
      val = '"'+val+'"'; 
     } 

     if(type !== 4) 
      res += ''+ val+','; 
    } 

    return res.substring(res, res.lastIndexOf(','))+']'; 
} 
1

हाल ही में मेरे पास एक समान उपयोग केस था। के बाद कोड कोई निर्भरता है और सभी ब्राउज़रों के लिए काम करता है:

function stringify(obj) { 
    var type = Object.prototype.toString.call(obj); 

    // IE8 <= 8 does not have array map 
    var map = Array.prototype.map || function map(callback) { 
    var ret = []; 
    for (var i = 0; i < this.length; i++) { 
     ret.push(callback(this[i])); 
    } 
    return ret; 
    }; 

    if (type === '[object Object]') { 
    var pairs = []; 
    for (var k in obj) { 
     if (!obj.hasOwnProperty(k)) continue; 
     pairs.push([k, stringify(obj[k])]); 
    } 
    pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1 }); 
    pairs = map.call(pairs, function(v) { return '"' + v[0] + '":' + v[1] }); 
    return '{' + pairs + '}'; 
    } 

    if (type === '[object Array]') { 
    return '[' + map.call(obj, function(v) { return stringify(v) }) + ']'; 
    } 

    return JSON.stringify(obj); 
}; 

stringify([{b: {z: 5, c: 2, a: {z: 1, b: 2}}, a: 1}, [1, 2, 3]])

'[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]'

stringify([{a: 1, b:{z: 5, c: 2, a: {b: 2, z: 1}}}, [1, 2, 3]])

'[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]'

3

अंडरस्कोर या Lodash का उपयोग करना:

var sortByKeys = function(obj) { 
    if (!_.isObject(obj)) { 
    return obj; 
    } 
    var sorted = {}; 
    _.each(_.keys(obj).sort(), function(key) { 
    sorted[key] = sortByKeys(obj[key]); 
    }); 
    return sorted; 
}; 

var sortedStringify = function() { 
    arguments[0] = sortByKeys(arguments[0]); 
    return JSON.stringify.apply(this, arguments); 
}; 

नवीनतम क्रोम और फ़ायरफ़ॉक्स में काम करता है।

यहाँ JSFiddle: http://jsfiddle.net/stchangg/ruC22/2/

+2

यह इस तथ्य पर निर्भर करता है कि अधिकांश ब्राउज़र जावास्क्रिप्ट ऑब्जेक्ट में कुंजी के क्रम को क्रम में रखने के क्रम में रखते हैं। [यह गारंटी नहीं है] (http://stackoverflow.com/q/5525795/247696) – Flimm

+1

हाँ, यह टूटा हुआ है। "var sorted = {};" एक अर्थहीन बयान है। वस्तुओं का आदेश नहीं दिया गया है जो इस प्रश्न को पहली जगह में पहुंचाते हैं। –

1

जावास्क्रिप्ट कुंजी आंतरिक रूप से अव्यवस्थित है। इस काम को करने के लिए आपको अपना खुद का स्ट्रिंगफायर लिखना है, इसलिए मैंने किया।

उपयोग:

JSONc14n.stringify(obj) 

स्रोत:

var JSONc14n = { 
    stringify: function(obj){ 
     var json_string, 
      keys, 
      key, 
      i; 

     switch(this.get_type(obj)){ 
      case "[object Array]": 
       json_string = "["; 
       for(i = 0; i < obj.length; i++){ 
        json_string += this.stringify(obj[i]); 
        if(i < obj.length - 1) json_string += ","; 
       } 
       json_string += "]"; 
       break; 
      case "[object Object]": 
       json_string = "{"; 
       keys = Object.keys(obj); 
       keys.sort(); 
       for(i = 0; i < keys.length; i++){ 
        json_string += '"' + keys[i] + '":' + this.stringify(obj[keys[i]]); 
        if(i < keys.length - 1) json_string += ","; 
       } 
       json_string += "}"; 
       break; 
      case "[object Number]": 
       json_string = obj.toString(); 
       break; 
      default: 
       json_string = '"' + obj.toString().replace(/["\\]/g, 
        function(_this){ 
         return function(character){ 
          return _this.escape_character.apply(_this, [character]); 
         }; 
        }(this) 
       ) + '"'; 
     } 
     return json_string; 
    }, 
    get_type: function(thing){ 
     if(thing===null) return "[object Null]"; 
     return Object.prototype.toString.call(thing); 
    }, 
    escape_character: function(character){ 
     return this.escape_characters[character]; 
    }, 
    escape_characters: { 
     '"': '\\"', 
     '\\': '\\\\' 
    } 
}; 
+0

वस्तुओं की एक सरणी पर मेरे लिए काम किया, धन्यवाद! बिल्कुल आवश्यक सभी नेस्टेड वस्तुओं के गुणों का आदेश दिया। ऊपर दिए गए पदों में से कुछ अन्य समाधानों का प्रयास किया, जिसके बाद कुछ tweaking काम नहीं कर रहे थे क्योंकि मुझे एम की आवश्यकता थी। पता है कि मैं यहां देर से कूद रहा हूं लेकिन हे ... –

+1

यह बूलियन मानों के लिए गलत और गलत के लिए गलत मान देता है। मैंने ''ऑब्जेक्ट बूलियन]' के लिए एक मामला जोड़ा जो 'jsonStr = obj कहता है? 'सत्य': 'झूठा'; 'मूल' JSON.stringify' के समान परिणाम प्राप्त करने के लिए। उपर्युक्त कोड के बारे में क्या अच्छा है कि यह देशी से केवल 4 गुना धीमा है, पैकेज में कोड https://github.com/substack/json-stable-stringify 10 गुना धीमा है (node.js 7.2.0 पर परीक्षण किया गया है)। –

8

आप JSON.sortify, एक छोटे से सहायक है कि मैंने लिखा कोशिश कर सकते हैं।

अब तक दिए गए उत्तर के विपरीत, यह

नेस्टिंग
  • संभाल कर सकते हैं संख्यात्मक कुंजियों के किसी भी स्तर के साथ
    • काम करता है
    • space parameter as well as the little used replacer parameter
    • स्वीकार करता है कुंजी में विशेष वर्ण निकल जाता है चक्रीय संदर्भों पर एक टाइपरर फेंकता है (जैसा कि यह होना चाहिए)
    • फ़िल्टर undefined v alues ​​और कार्यों
    • सम्मान toJSON()
  • +0

    ['json-stable-stringify'] भी है (https://github.com/substack/json-stable-stringify)। ऐसा लगता है कि यह थोड़ा पुराना और अधिक परिपक्व है। मेरे लिए प्रासंगिक महत्वपूर्ण अंतर यह है कि यह एक कस्टम तुलना समारोह का समर्थन करता है। मेरे मामले में मैं मूल्य से क्रमबद्ध करना चाहता हूं क्योंकि मेरी ऑब्जेक्ट आवृत्ति सारणी हैं और मैं JSON फ़ाइलों की अधिकतम मानव उपयोगिता चाहता हूं। मैंने वास्तव में अभी तक मॉड्यूल की कोशिश नहीं की है। – hippietrail

    +2

    @hippietrail मैंने पहले देखा है, और आप निश्चित रूप से इसका उपयोग कर सकते हैं। प्रमुख आर्किटेक्चरल अंतर यह है कि JSON.sortify JSON.stringify के साथ अधिकतम संगतता प्राप्त करने का प्रयास करता है, यानी आप केवल 'JSON.stringify = JSON.sortify' को ओवरराइट कर सकते हैं और सुनिश्चित कर सकते हैं कि कुछ भी टूट नहीं जाता है। जेसन-स्थिर-स्ट्रिंग के साथ ऐसा नहीं है। उदाहरण के लिए, यह [replacer पैरामीटर] (http://www.dyn-web.com/tutorials/php-js/json/filter.php) प्रदान नहीं करता है, और यह चक्रीय मूल्यों आदि पर क्रैश होता है – ThomasR

    +0

    @ थॉमसआर: हां मैंने देखा कि एक बार जब मैंने इसके साथ खेला था। मॉड्यूल इस धागे में उल्लेख करने योग्य है लेकिन पूरे अलग जवाब का नहीं। – hippietrail

    संबंधित मुद्दे

     संबंधित मुद्दे