2010-05-14 15 views
17

मेरे जेसन को बदलने के लिए सबसे तेज़ और आसान तरीका क्या है, जिसमें ऑब्जेक्ट्स का डेटा शामिल है, जिसमें वास्तविक ऑब्जेक्ट्स संलग्न हैं?जेसन डेटा को ऑब्जेक्ट्स में संलग्न तरीकों से बदलने का सबसे आसान तरीका?

उदाहरण के द्वारा, मैं फल वस्तुओं जो बारी में बीज की एक सरणी इस प्रकार के होते हैं की एक सरणी के साथ एक fruitbowl के लिए डेटा प्राप्त:

{"fruitbowl": [{ 
    "name": "apple", 
    "color": "red", 
    "seeds": [] 
    },{ 
    "name": "orange", 
    "color": "orange", 
    "seeds": [ 
     {"size":"small","density":"hard"}, 
     {"size":"small","density":"soft"} 
    ]} 
} 

बस इतना ही अच्छा और अच्छा लेकिन ग्राहक पर नीचे है हम इस फल के साथ सामान करते हैं, जैसे कि यह और संयंत्र के पेड़ खा ...

var fruitbowl = [] 
function Fruit(name, color, seeds){ 
    this.name = name 
    this.color = color 
    this.seeds = seeds 
    this.eat = function(){ 
     // munch munch 
    } 
} 
function Seed(size, density){ 
    this.size = size 
    this.density = density 
    this.plant = function(){ 
      // grow grow 
    } 
} 

मेरे ajax की सफलता दिनचर्या वर्तमान में वर्तमान में बात से अधिक पाशन और बदले में प्रत्येक वस्तु के निर्माण और यह अभी तक बीज से हैंडल नहीं करता है, क्योंकि इससे पहले कि मैं बीज constru पर लूपिंग जाओ ctors मैं सोच रहा हूँ

क्या कोई बेहतर तरीका नहीं है?

success: function(data){   
     fruitbowl.length = 0 
     $.each(data.fruitbowl, function(i, f){ 
      fruitbowl.push(new Fruit(f.name, f.color, f.seeds)) 
     }) 

मैं वस्तुओं से अधिक पाशन के रूप में वे कर रहे हैं और सभी तरीकों संलग्न छानबीन नहीं की है। क्या इससे काम हो जायेगा?

+0

अतिरिक्त क्रेडिट के लिए: मुझे किसी बिंदु पर "उदाहरण" के साथ अपने फल और बीज की पहचान करने की आवश्यकता हो सकती है। –

उत्तर

2

वस्तु निर्माता को डेटा पास फिर "विस्तार" jQuery का उपयोग डेटा और तरीकों गठबंधन करने के लिए:

function Fruit(data){ 
    $.extend(this, data) 
    this.eat = function(){ 
     // munch munch 
    } 
} 
... 
     $.each(data.fruitbowl, function(i, f){ 
      fruitbowl.push(new Fruit(f)) 
     }) 

तुम अब भी छोरों शामिल है; और नेस्टेड ऑब्जेक्ट्स (जैसे बीज) के लिए मैन्युअल रूप से कोड लूप करना होगा, लेकिन समस्या को दूर करने के लिए अभी भी एक बहुत ही आसान तरीका है।

2

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

जो आप वर्तमान में कर रहे हैं वह सबसे अच्छा समाधान है; और आप instanceof का उपयोग करने में सक्षम होंगे।

आप रोमांच महसूस कर रहे हैं तो आप AJAX के बजाय JSONP JSONP प्रतिक्रिया के साथ की तरह कुछ के लिए देख उपयोग कर सकते हैं,:

buildFruitbowl([new Fruit("orange", "blue", [new Seed("small", "hard"), new Seed("big", "soft")]), new Fruit("banana", "yellow", [new Seed("small", "hard"), new Seed("big", "soft")])]); 

कौन सा आप अपने सभी वस्तु पाशन क्या करने वाले की बचत होगी, और तुम हूँ अपने फल और बीज प्राप्त करें कि आप कैसे चाहते हैं (और instanceof समर्थन); हालांकि मैं अभी भी जो कुछ भी कर रहा हूं उससे चिपके रहूंगा।

अपने केले को बढ़ने के सर्वश्रेष्ठ दिखने।

+2

"अपने केले को बढ़ने के सर्वश्रेष्ठ दिखने" - पहले कभी नहीं सुना। – Anurag

1

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

"स्ट्रिंग" विधि में एक समान वैकल्पिक पैरामीटर है।

+1

चेतावनी: जब भी आप रिवाइवर का उपयोग करने का निर्णय लेते हैं तो आपको jozilla/firefox <3.6 देशी JSON json2.js के साथ ओवरराइट करने की आवश्यकता होती है। पुनरुद्धार कार्यान्वयन में एक दस्तावेजी बग है। –

2

आप प्रकार की जानकारी स्टोर करने के लिए JSON संरचना को संशोधित कर सकते हैं। यदि आपके पास आगे और आगे क्रमबद्ध करने और deserialize करने के लिए बहुत सारी वस्तुएं हैं, तो यह प्रत्येक ऑब्जेक्ट के लिए समय लिखने का कस्टम कोड सहेज लेगा।

यह भी ध्यान दें, यह JSON संरचना को संशोधित करता है और प्रत्येक कस्टम ऑब्जेक्ट में __type__ संपत्ति जोड़ता है। मुझे लगता है कि अलग कॉन्फ़िगरेशन फ़ाइलों को रखने से यह एक क्लीनर दृष्टिकोण है। तो आगे की हलचल के बिना, इस यह मूल रूप से कैसे काम करता है:

var fruitBowl = {..}; 
fruitBowl[0].eat(); 
fruitBowl[1].seeds[0].plant(); 

कॉल वस्तु पर क्रमानुसार एक JSON प्रतिनिधित्व वस्तुओं फिर से संगठित करने JSON इनकोडिंग स्ट्रिंग पर

var json = fruitBowl.serialize(); 

कॉल deserialize पाने के लिए

var resurrected = json.deserialize(); 

अब आप वस्तुओं पर गुणों और कॉल विधियों तक पहुंच सकते हैं:

resurrected[0].eat(); 
resurrected[1].seeds[0].plant(); 

यह गहरा घोंसला वाले वस्तुओं के किसी भी स्तर के लिए काम करता है, हालांकि यह अब के लिए थोड़ी छोटी गाड़ी हो सकती है। इसके अलावा यह क्रॉस-ब्राउजर नहीं है (केवल क्रोम पर परीक्षण किया जाता है)। चूंकि deserializer किसी ऑब्जेक्ट के कन्स्ट्रक्टर फ़ंक्शन से परिचित नहीं है, इसलिए यह मूल रूप से किसी भी पैरामीटर को पार किए बिना प्रत्येक कस्टम ऑब्जेक्ट बनाता है। मैंने jsfiddle पर http://jsfiddle.net/kSATj/1/ पर एक कामकाजी डेमो सेट किया है।

निर्माता समारोह दो तरीके यह वस्तुओं जावास्क्रिप्ट में सीधे

  1. निर्मित किया जा सकता
  2. JSON से पुन: तैयार

सभी कंस्ट्रक्टर्स निर्माण को समायोजित करने की आवश्यकता होगी है के लिए खाते में करने के लिए संशोधित किया जा सकता था दोनों सिरों से, इसलिए प्रत्येक प्रॉपर्टी को डिफ़ॉल्ट फ़ॉलबैक मान असाइन करने की आवश्यकता होती है, जिसमें कुछ भी पारित नहीं होता है।

function SomeObject(a, b) { 
    this.a = a || false; // defaultValue can be anything 
    this.b = b || null; // defaultValue can be anything 
} 

// one type of initialization that you can use in your code 
var o = new SomeObject("hello", "world"); 

// another type of initialization used by the deserializer 
var o = new SomeObject();; 
o.a = "hello"; 
o.b = "world"; 

संदर्भ के लिए, संशोधित JSON लगता है:

function isNative(object) { 
    if(object == null) { 
     return true; 
    } 

    var natives = [Boolean, Date, Number, String, Object, Function]; 
    return natives.indexOf(object.constructor) !== -1; 
} 

(प्रकार की जानकारी के साथ JSON में एक वस्तु को धारावाहिक:

{"fruitbowl": 
    [ 
     { 
      "__type__": "Fruit", 
      "name": "apple", 
      "color": "red", 
      "seeds": []   
     }, 
     { 
      "__type__": "Fruit", 
      "name": "orange", 
      "color": "orange", 
      "seeds": 
      [ 
       { 
        "__type__": "Seed", 
        "size": "small", 
        "density": "hard" 
       }, 
       { 
        "__type__": "Seed", 
        "size": "small", 
        "density": "soft" 
       } 
      ] 
     } 
    ] 
} 

यह सरल प्रकारों की पहचान करने के लिए सिर्फ एक सहायक समारोह है संरक्षित):

Object.prototype.serialize = function() { 
    var injectTypes = function(object) { 
     if(!isNative(object)) { 
      object.__type__ = object.constructor.name; 
     } 

     for(key in object) { 
      var property = object[key]; 
      if(object.hasOwnProperty(key) && !isNative(property)) { 
       injectTypes(property); 
      } 
     } 
    }; 

    var removeTypes = function(object) { 
     if(object.__type) { 
      delete object.__type__; 
     } 
     for(key in object) { 
      var property = object[key]; 
      if(object.hasOwnProperty(key) && !isNative(property)) { 
       removeTypes(property); 
      } 
     } 
    } 

    injectTypes(this); 
    var json = JSON.stringify(this); 
    removeTypes(this); 

    return json; 
}; 

deserialize (कस्टम वस्तुओं का पुनर्निर्माण के साथ):

String.prototype.deserialize = function() { 
    var rawObject = JSON.parse(this.toString()); 

    var reconstruct = function(object) { 
     var reconstructed = {}; 

     if(object.__type__) { 
      reconstructed = new window[object.__type__](); 
      delete object.__type__; 
     } 
     else if(isNative(object)) { 
      return object; 
     } 

     for(key in object) { 
      var property = object[key]; 

      if(object.hasOwnProperty(key)) { 
       reconstructed[key] = reconstruct(property); 
      } 
     } 

     return reconstructed; 
    } 

    return reconstruct(rawObject); 
}; 
+0

वाह, प्रयास के लिए पूर्ण अंक! आसान होने के लिए बहुत से नहीं। __type__ पास करने का विचार उल्लेख किया गया है। –

+0

मैं मानता हूं, यदि आपके पास कुछ ऑब्जेक्ट्स हैं तो यह बहुत उपयोगी नहीं है। जेएसओएन से हाथों से बिल्डिंग ऑब्जेक्ट्स निश्चित रूप से उस मामले में एक बेहतर और आसान दृष्टिकोण है।मुझे लगता है कि मैंने पहले ही अपने समाधान के साथ कमियों का उल्लेख किया है - * छोटी गाड़ी *, * क्रॉस-ब्राउजर * नहीं, और * जेएसओएन * प्रदूषित करता है, लेकिन थोड़ा और प्रयास के साथ इस दृष्टिकोण को उन वस्तुओं की संख्या के रूप में भुगतान करना शुरू करना चाहिए जिनकी आवश्यकता है पुनर्निर्मित किया जाना चाहिए। विचार के लिए – Anurag

0

जॉन,

उम्मीद है कि नहीं भी यहाँ में चिप के लिए देर से। पिछले हफ्ते मुझे बहुत ही समान समस्या थी और इसे जेएस के निम्नलिखित टुकड़े के साथ हल किया गया (इसे आसानी से jquery में भी परिवर्तित किया जा सकता है।)।

यहाँ आधार उपयोग है:

$(document).ready(function() { 
     var bowl = { "fruitbowl": [{ 
      "name": "apple", 
      "color": "red", 
      "seeds": [] 
     }, 
     { 
      "name": "orange", 
      "color": "orange", 
      "seeds": [ 
      { "size": "small", "density": "hard" }, 
      { "size": "small", "density": "soft"}] 
     } 
     ] 
     }; 

     var serialized = jsonToObject.serialize(bowl); 
     var deserialized = jsonToObject.deserialize(serialized); 
     // basic tests on serialize/deserializing... 
     alert(deserialized.fruitbowl[0].name); 
     alert(deserialized.fruitbowl[1].seeds[0].density); 
    }); 

और यहाँ jsonToObject.js फ़ाइल है:

आशा है कि यह मदद करता है ...

जिम

[संपादित करें] - आप निश्चित रूप से भी यानी ऊपर उत्कृष्ट उदाहरण के साथ रखते हुए, में अपने प्रोटोटाइप हस्ताक्षर दो कार्यों दे सकता है ..

String.prototype.deserialize = समारोह () {...} Object.prototype.serialize = function() {...}

+0

धन्यवाद। deserialize हमेशा तारों पर किया जाता है तो इसे आदर्श रूप से स्ट्रिंग प्रोटोटाइप में जोड़ा जाना चाहिए। – Anurag

+0

हां, मैंने एक स्थानीय संस्करण किया जो प्रोटोटाइप सिग का इस्तेमाल करता था, लेकिन मेरा उदाहरण छोड़ दिया गया है क्योंकि यह दिया गया है कि यह आपका दृष्टिकोण लेता है - थोड़ा विविधता देता है :) बीटीडब्ल्यू - आपको अभी भी अपने उदाहरण में स्ट्रिंग करने के लिए हस्ताक्षर को अपडेट करने की आवश्यकता है (http://jsfiddle.net/kSATj/) - बस अगर आप इसे अनदेखा करते हैं;) –

+0

विविधता हमेशा अच्छी होती है :) और स्ट्रिंग टिप के लिए धन्यवाद। बस मेरा उदाहरण अपडेट किया गया – Anurag

1

यह वास्तव में मुझे कुछ समय लिया यह पता लगाने की है, मैं वास्तव में इस पर नहीं और अधिक पृष्ठों देखते हैं हैरान हूँ।

जैसा कि @ पॉइंटी ने इंगित किया है, जेएसओएन के पास एक रिवाइवर फ़ंक्शन है जिसका उपयोग पार्स परिणाम इनलाइन को प्रतिस्थापित करने के लिए किया जा सकता है जिससे आप दूसरी बार पेड़ से बचने से बच सकते हैं। JSON पृष्ठ दस्तावेज़ पुन: सक्रिय (मेरी राय में थोड़ा कमजोर) - http://json.org/js.html

रिविवर ईसीएमए 5 का हिस्सा है और फ़ायरफ़ॉक्स, वेबकिट (ओपेरा/क्रोम), और JSON2.js में समर्थित है।

यहां JSON दस्तावेज़ के आधार पर एक कोड उदाहरण है। आप देख सकते हैं कि हम कुत्ते पर एक प्रकार की संपत्ति सेट कर रहे हैं और उसके बाद एक रिवाइवर फ़ंक्शन का उपयोग कर रहे हैं जो उस प्रकार की संपत्ति को पहचानता है।

function Dog(args) { 
    this.name = args.name; 
    this.bark = function() { 
     return "bark, bark, my name is " + this.name; 
    }; 
    this.toJSON = function() { 
     return { 
      name: this.name, 
      type: 'Dog' // this.constructor.name will work in certain browsers/cases 
     } 
    } 
}; 

var d = new Dog({name:'geti'}); 

var dAsJson = JSON.stringify(d); 
var dFromJson = JSON.parse(dAsJson, function (key, value) { 
    var type; 
    if (value && typeof value === 'object') { 
     type = value.type; 
     if (typeof type === 'string' && typeof window[type] === 'function') { 
      return new (window[type])(value); 
     } 
    } 
    return value; 
} 
); 

मुझे उनके उदाहरण के बारे में कुछ चिंताएं हैं। पहला यह है कि यह वैश्विक (खिड़की पर) निर्माता पर निर्भर करता है। दूसरी बात यह है कि उस दुष्ट जेएसओएन में एक सुरक्षा चिंता है जो हमें अपने JSON में एक प्रकार की संपत्ति जोड़कर किसी भी निर्माता को कॉल करने के लिए कह सकती है।

मैंने प्रकारों और उनके रचनाकारों की एक स्पष्ट सूची चुना है। यह केवल उन रचनाकारों को सुनिश्चित करता है जिन्हें मैं जानता हूं सुरक्षित हैं और मुझे कस्टम प्रकार मैपिंग दृष्टिकोण का उपयोग करने की इजाजत देता है यदि मुझे पसंद है (कन्स्ट्रक्टर नाम के आधार पर और यह वैश्विक स्थान पर है)। मैं यह भी सत्यापित करता हूं कि JSON ऑब्जेक्ट में एक प्रकार है (कुछ नहीं हो सकता है और उनका सामान्य रूप से इलाज किया जाएगा)।

var jsonReviverTypes = { 
    Dog: Dog 
}; 

var dAsJsonB = JSON.stringify(d); 
var dFromJsonB = JSON.parse(dAsJsonB, function (key, value) { 
    var type; 
    if (value && typeof value === 'object' && value.type) { 
     type = value.type; 
     if (typeof type === 'string' && jsonReviverTypes[type]) { 
      return new (jsonReviverTypes[type])(value); 
     } 
    } 
    return value; 
}); 

ध्यान दें, एफएफ 3.6 JSON.replacer विधि में एक बग के रूप में @Sky बताया है और यहाँ दस्तावेज़ तैयार किया है - http://skysanders.net/subtext/archive/2010/02/24/confirmed-bug-in-firefox-3.6-native-json-implementation.aspx। उपर्युक्त समाधान के लिए मैं प्रतिस्थापन का उपयोग करने के बजाए ऑब्जेक्ट पर toJSON का उपयोग करके इसके आसपास काम करता हूं।

2

ES5 Object.create

का उपयोग करते हुए, बस स्थिर तो अपने वस्तुओं को परिभाषित Object.create का उपयोग उन्हें विस्तार करने के लिए।

यह रूप में सरल रूप में Object.create(Bowl, transform(data));

// declare 3 Objects to use as prototypes for your data 
var Fruit = { 
    eat: function() { } 
} 

var Seed = { 
    plant: function() { } 
} 

var Bowl = {}; 

// data object 
var data = { ... }; 


// Transform JSON to a valid defineProperties hash. 
Object.create(Bowl, transform(data)); 

आप को बदलने समारोह को परिभाषित करने और अधिक महत्वपूर्ण बात यह डेटा की नेस्टेड सरणियों के ऑब्जेक्ट प्रकार बताने के लिए की आवश्यकता होगी है।

// hash map of property names of arrays to the Object they should prototype from. 
var collectionClassHash = { 
    fruitbowl: Fruit, 
    seeds: Seed 
} 

var transform = function(obj) { 
    // return value 
    var ret = {}; 
    // for each key 
    Object.keys(obj).forEach(function(key) { 
    // value of key 
    var temp = obj[key]; 
    // if array 
    if (Array.isArray(temp) { 
     // override value with an array of the correct objects 
     temp = obj[key].map(function(val) { 
     // recurse for nested objects 
     return Object.create(collectionClassHash[key], transform(val)); 
     }); 
    } 
    // define getter/setter for value 
    ret[key] = { 
     get: function() { return temp; }, 
     set: function(v) { temp = v; } 
    } 
    }); 
    return ret; 
} 
संबंधित मुद्दे