2012-12-25 16 views
9

JSON, eval veya JSON.parse kullanarak javascript'te bir nesneye kolayca yüklenebilir.JSON'dan orijinal nesne/tür nasıl geri yüklenir?

Fakat eğer uygun bir "sınıf" işlevi varsa, JSON verilerini ona nasıl alırsınız?

E.g.

function Person(name) { 
    this.name=name; 
    this.address = new Array(); 
    this.friendList; 

    this.promote = function(){ 
    // do some complex stuff 
    } 
    this.addAddress = function(address) { 
    this.address.push(address) 
    } 
} 

var aPersonJSON = '{\"name\":\"Bob\",\"address\":[{\"street\":\"good st\",\"postcode\":\"ADSF\"}]}' 

var aPerson = eval("(" + aPersonJSON + ")"); // or JSON.parse 
//alert (aPerson.name); // Bob 
var someAddress = {street:"bad st",postcode:"HELL"}; 
//alert (someAddress.street); // bad st 
aPerson.addAddress(someAddress); // fail! 

püf noktası ben JSON'dan uygun Kişi örneklerini oluşturmak gerekiyor, ama olsun bütün dilsiz nesnedir. Prototiplerle bir şey yapmanın mümkün olup olmadığını merak ediyorum?

JSON'un her satırını ayrıştırmak ve her bir değişkeni, karşılık gelen işlev özniteliklerine atamak istemiyorum, ki bu çok zor olurdu. Gerçek JSON ve sahip olduğum işlevler yukarıdaki örneklerden daha karmaşıktır.

JSON dizesinde işlevlerin JSONify olabileceğini varsayarak, ancak sonuç verilerinin mümkün olduğunca küçük tutulması gerektiğinden, bu yalnızca bir seçenek değil - yalnızca verileri depolamak ve yüklemek istiyorum, javascript yöntemler için kod.

Ayrıca yardımcı olabiliyorsam JSON tarafından yüklenen verileri bir alt nesne olarak koymak zorunda kalmak istemiyorum (ancak tek yol olabilir), ör.

function Person(name) { 
    this.data = {}; 
    this.data.name=name; 
} 

var newPerson = new Person(""); 
newPerson.data = eval("(" + aPersonJSON + ")"); 
alert (newPerson.data.name); // Bob 

Herhangi bir fikir?

+2

Lütfen JSON'yi ayrıştırmak için değil "JSON.parse" (http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) ve "eval" kullanmayın. Eğer hedef tarayıcılar JSON.parse'ı desteklemiyorsa (yani IE7 ya da daha eski), Crockford'un json.js'si aracılığıyla bir 'swim' (dahili olarak değerlendirmekle birlikte aynı zamanda akıl sağlığı doğrulaması kullanır) ya da json2'yi kullanır. js' kullanılabilir durumda. –

+0

Merhaba, Sorun aynı türden olmayan nesneyi üreten, değerlendirme veya ayrıştırma değildir, JSON'u Kişi işlevine sokmanın bir yolunu bulmaya çalışıyorum. Bu konuda bir fikrin var mı? –

+0

@JohnLittle asla kullanmayın !, pek çok güvenlik sorununun kaynağıdır (kod enjeksiyonu vb.) [Bunu okuyun] (http://stackoverflow.com/questions/197769/when-is-javascripts-eval-not-evil – thepoosh

cevap

2

En kolay yol, dizgeni ayrıştırmak için JSON.parse kullanıp nesneyi işleve iletmektir. JSON.parse, çevrimiçi json2 kütüphanesinin bir parçasıdır.

+1

JSON yöntemleri modern tarayıcılarda mevcuttur ... eski tarayıcılarda geri dönüş olarak kitaplığı kullanın – charlietfl

+0

'JSON.stringify() işlevi ** * ayrıştırma * için ** değil; Bir nesneyi * bir JSON dizesine * çevirmek içindir. – Pointy

+0

Merhaba, bu karmaşıklık, karmaşık kompleksi nesnelere nasıl dönüştürecek? Sadece geçiş yapamazsınız - nesneyi geçmek için çok karmaşık bir şey yazmazsam, her bir alt-nesneyi ve veri öğesini, özellikle de sık sık değiştiği gibi yapmak istemediğim Şahıs objegresine kopyalar. –

8

Birçok çerçeve, alanları bir nesneden diğerine kopyalayacak bir 'uzantı' işlevi sunar. İstediğinizi yapmak için JSON.parse ile birleştirebilirsiniz.

newPerson = new Person(); 
_.extend(newPerson, JSON.parse(aPersonJSON)); 

gibi bir şey eklemek istemiyorsanız

her zaman sadece işlevini genişletmek veya kendi yazma kopyalayabilir vurgulamaktadır.

CoffeeScript örneği Canım sıkıldı çünkü:

JSONExtend = (obj, json) -> 
    obj[field] = value for own field, value of JSON.parse json 
    return obj 

class Person 
    toString: -> "Hi I'm #{@name} and I'm #{@age} years old." 


dude = JSONExtend new Person, '{"name":"bob", "age":27}' 
console.log dude.toString() 
+0

Çeşitli gazap verme riski altında, Coffeescript için +1! –

0

I; çok fazla bu işe, ama aPerson.addAddress çalışmaması gerektiğini, neden doğrudan nesnesine atama değilim?

aPerson.address.push(someAddress); 
alert(aPerson.address); // alert [object object] 
16

Bir reviver işlevi kullanmak gerekir: Sadece birisi ihtiyacı durumunda gerçekten

// Registry of types 
var Types = {}; 

function MyClass(foo, bar) { 
    this._foo = foo; 
    this._bar = bar; 
} 
Types.MyClass = MyClass; 

MyClass.prototype.getFoo = function() { 
    return this._foo; 
} 

// Method which will provide a JSON.stringifiable object 
MyClass.prototype.toJSON = function() { 
    return { 
    __type: 'MyClass', 
    foo: this._foo, 
    bar: this._bar 
    }; 
}; 

// Method that can deserialize JSON into an instance 
MyClass.revive = function(data) { 
    // TODO: do basic validation 
    return new MyClass(data.foo, data.bar); 
}; 

var instance = new MyClass('blah', 'blah'); 

// JSON obtained by stringifying an instance 
var json = JSON.stringify(instance); // "{"__type":"MyClass","foo":"blah","bar":"blah"}"; 

var obj = JSON.parse(json, function(key, value) { 
    return key === '' && value.hasOwnProperty('__type') 
    ? Types[value.__type].revive(value) 
    : this[key]; 
}); 

obj.getFoo(); // blah 

Başka hiçbir yolu ...

+1

Bu işlevi "reviver" olarak adlandırmak için bir sözleşme var mı? – Bergi

+1

JSON nesnesinin özelliklerinde, yöntem (ve resmi argümana) bir reviver olarak adlandırılır. –

1

, burada bu (saf javascript fonksiyonu uzatmak olduğunu Belli ki bir nesne tanımına aittir).

this.extend = function (jsonString){ 
    var obj = JSON.parse(jsonString) 
    for (var key in obj) { 
     this[key] = obj[key] 
     console.log("Set ", key ," to ", obj[key]) 
     } 
    } 

console.log kaldırmak unutmayın: Geç partiye P

1

Biraz ama bu birilerini yardımcı olabilir. Ben böyle olsun çözdük nasıl, ES6 sözdizimi:

class Page 
{ 
    constructor() { 
     this.__className = "Page"; 
    } 

    __initialize() { 
     // Do whatever initialization you need here. 
     // We'll use this as a makeshift constructor. 
     // This method is NOT required, though 
    } 
} 

class PageSection 
{ 
    constructor() { 
     this.__className = "PageSection"; 
    } 
} 

class ObjectRebuilder 
{ 
    // We need this so we can instantiate objects from class name strings 
    static classList() { 
     return { 
      Page: Page, 
      PageSection: PageSection 
     } 
    } 

    // Checks if passed variable is object. 
    // Returns true for arrays as well, as intended 
    static isObject(varOrObj) { 
     return varOrObj !== null && typeof varOrObj === 'object'; 
    } 

    static restoreObject(obj) { 
     let newObj = obj; 

     // At this point we have regular javascript object 
     // which we got from JSON.parse. First, check if it 
     // has "__className" property which we defined in the 
     // constructor of each class 
     if (obj.hasOwnProperty("__className")) { 
      let list = ObjectRebuilder.classList(); 

      // Instantiate object of the correct class 
      newObj = new (list[obj["__className"]]); 

      // Copy all of current object's properties 
      // to the newly instantiated object 
      newObj = Object.assign(newObj, obj); 

      // Run the makeshift constructor, if the 
      // new object has one 
      if (newObj.__initialize === 'function') { 
       newObj.__initialize(); 
      } 
     } 

     // Iterate over all of the properties of the new 
     // object, and if some of them are objects (or arrays!) 
     // constructed by JSON.parse, run them through ObjectRebuilder 
     for (let prop of Object.keys(newObj)) { 
      if (ObjectRebuilder.isObject(newObj[prop])) { 
       newObj[prop] = ObjectRebuilder.restoreObject(newObj[prop]); 
      } 
     } 

     return newObj; 
    } 
} 

let page = new Page(); 
let section1 = new PageSection(); 
let section2 = new PageSection(); 

page.pageSections = [section1, section2]; 

let jsonString = JSON.stringify(page); 
let restoredPageWithPageSections = ObjectRebuilder.restoreObject(JSON.parse(jsonString)); 

console.log(restoredPageWithPageSections); 

Sayfanız dizisi sınıfının PageSection 2 nesneler içeren, sınıfının Page bir nesne olarak restore edilmelidir. Özyineleme, derinliğe bakılmaksızın son nesneyi sonuna kadar çalışır. @Sean Kinsey'in cevabı çözümüme ulaşmamı sağladı.

İlgili konular