2012-10-19 127 views
3

我已經看到了非常類似的問題,但我不能確定他們是否清楚地回答 - 也許我有點緊張,對不起。自定義對象到JSON然後返回到自定義對象?

我想讓自己的對象具有方便性(清晰度),稱之爲CardboardBox()。它不會包含代碼,只包含數據。我想將它寫入數據庫並稍後再讀取,但很明顯,它在讀回時是Object()。所有我能想到的,找出它曾經是是:

  1. 有一個成員變量type我設置爲CARDBOARD_BOX
  2. 實例化一個新CarbardBox()和使用的功能(在框中)複製Object()的屬性到新的CardboardBox()對象

有沒有更好的方法來做到這一點?我很確定我可以更改實際的類型。

function CardboardBox() { 
    this.type = "CARDBOARD_BOX" 
    this.name = "No set"; 
    this.populate = new function(obj) { 
    // populate this object with obj properties 
} 

var box = new CarboardBox(); // CarboardBox 
box.name = "My Box"; 
send = JSON.stringyfy(box); 
. 
. 
. 
obj = JSON.parse(send); // Object 

if (obj.type == "CARDBOARD_BOX") { 
    savedBox = new CardboardBox(); 
    savedBox.populate(obj); 
} 

在此先感謝... 史蒂夫

[編輯]我的測試代碼。

function CardboardBox(n) { 
    this.name = n; 
} 

var box = new CardboardBox("My Box"); 
send = JSON.stringify(box); // JSON CarboardBox() 

obj = JSON.parse(send, function fn(obj) { // Object() returned 
    log("OB: "+obj.type); 
    return obj.type === 'CardboardBox' ? new CardboardBox(obj) : CardboardBox; 
});  
console.log(obj); 

輸出是:

OB: undefined utils.js:40 
OB: undefined utils.js:40 
function CardboardBox(n) { 
    this.name = n; 
} 
+4

看看JSON.parse和JSON.stringify參數。您可以爲每個對象定製回調。 'JSON.parse(obj,fn);函數fn(obj){return obj.type ==='a'?新的A(obj):a;如果我有時間的話,我會寫一個正確的答案。抱歉。 –

+0

感謝您的回覆。非常感謝,但我現在更加困惑。如果我在'CardboardBox()'中使用函數(fn),那麼從'JSON.parse()'返回的是'CarboardBox()'的構造函數。 'obj.type'總是未定義的。我想我錯過了一些東西...... – Steve

+0

@Steve:你必須設置'.type',並且你沒有正確地使用參數(第一個參數不是'obj',因爲建議)。請參閱http://jsfiddle.net/LSUJ9/。 – pimvdb

回答

5

一個可能的解決方案是:

function CardboardBox(n) { 
    if(typeof(n) == 'string') { 
    //build from name string 
    this.name = n; 
    } else { 
    //build from object 
    this.name = n.name; 
    } 

    //add in this object's "type" in a place 
    //that is unlikely to exist in other JSON strings 
    this.__type = 'CardboardBox'; 
} 

var box = new CardboardBox("My Box"); 
send = JSON.stringify(box), // JSON CarboardBox() 
obj = JSON.parse(send, function(key, val) { 
    //if this is an object, and is CardboardBox 
    if(typeof(val) === 'object' && val.__type === 'CardboardBox') 
     return new CardboardBox(val); 

    return val; 

    //or if your object is in a context (like window), and there are many of 
    //them that could be in there, you can do: 
    // 
    //if(typeof(val) === 'object' && context[val.__type]) 
    // return new context[val.__type](val); 
}); 


console.log(obj); 

對象類型基本上儲存在你知道要尋找供以後解析JSON當一個地方。如果你有多個對象可以在一個範圍內實例化,那麼第二個解析方法可能更合適。這也將佔據JSON中的對象而不是CarboardBox s。

編輯這是一個jsFiddle這個方法在行動。

+0

是的,這幾乎是我的解決方案。我只是想知道是否有更好的方法。希望JavaScript有適當的類。猜猜我會結束某種Java Bean類型的事情。 – Steve

+0

它不是JavaScript「沒有適當的類」,它是JSON格式不支持自定義對象。所以你不得不解決這個問題,就我所知,這個(或者一個變體)是實現它的唯一方法。即使使用Backbone或某個框架將其抽象出來,它也只是在幕後做類似的事情。 – Chad

1

總的來說,你是正確的:Javascript沒有任何內置的方式來超越普通對象序列化任何東西,因此去往和來自JSON的反序列化時不會產生特定的類。所以你需要自己完成序列化/反序列化,或者使用一個提供一些支持的庫。

我個人比較喜歡Backbone.js這個問題,因爲它處理序列化和反序列化相當好。您可以定義一個模型類,其中包括一種將數據以序列化形式保存到服務器的方法,以及將其反序列化回模型的方法。這裏的關鍵設計問題是反序列化進行知道你要反序列化的模型:

  • 你傳遞一個你要麼調用myModel.fetch()從基於模型ID服務器獲取數據,或
  • 將大量新數據傳遞給模型構造函數:new Model(serializedData)
  • 您將多個模型的數據數組傳遞給知道模型類型的集合:new ModelCollection(arrayOfSerializedData)

Backbone不做的是處理未知類型的類型轉換數據。當我處理這個問題時,我通常會做類似於@ Chad的迴應,但是使用中介;你可以認爲這是一個代理模型,或作爲工廠:

var classes = { 
    CardboardBox: ..., 
    AluminumBox: ... 
} 

function Deserializer(json) { 
    // parse if you're actually dealing with a string 
    var data = JSON.parse(json), 
     // now look for some custom type flag - you'll need to set this yourself 
     type = data.type, 
     // class lookup, perhaps with a default 
     Cls = classes[type] || DefaultType; 
    return new Cls(data); 
} 

var obj = new Deserializer(send); 
obj instanceof CardboardBox; // should work 

這仍然依賴於定製標誌切換類型,雖然 - 我不知道有這周圍的任何方式。

+0

所有優秀的答案。謝謝。我最終可能會編寫我自己的JSON包裝器。如果我在反序列化後無法將對象放入正確的類中,代碼會變得混亂,並且/或者最終我會在對象上做額外的工作。 – Steve