javascript 自定义对象到 JSON 然后返回自定义对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12975430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 17:32:02  来源:igfitidea点击:

Custom object to JSON then back to a custom object?

javascriptjsonobject

提问by Steve

I've seen very similar questions to this, but I can't quite decide if they was answered clearly - maybe I'm being a bit dense, sorry.

我见过与此非常相似的问题,但我无法确定是否清楚地回答了它们 - 也许我有点密集,抱歉。

I want to have the convenience (and clarity) of my own object, call it a CardboardBox(). It won't contain code, just data. I want to write this to a database and read it back later, but obviously, it is a type Object()when it's read back. All I can think of to find out what it used to be is:

我想拥有自己的对象的便利性(和清晰性),将其称为CardboardBox(). 它不包含代码,只包含数据。我想将其写入数据库并稍后读回,但很明显,它Object()在回读时是一种类型。我所能想到的就是找出它曾经是什么:

  1. Have a member variable typethat I set to CARDBOARD_BOX
  2. Instantiate a new CarbardBox()and use a function (in the box) to copy the properties of Object()to the new CardboardBox()object
  1. 有一个type我设置为 CARDBOARD_BOX的成员变量
  2. 实例化一个新对象CarbardBox()并使用一个函数(在框中)将 的属性复制Object()到新CardboardBox()对象

Is there a better way of doing this? I'm pretty sure I can change the actualtype.

有没有更好的方法来做到这一点?我很确定我可以更改实际类型。

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);
}

Thanks in advance... Steve

提前致谢...史蒂夫

[edit] My test code.

[编辑] 我的测试代码。

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);

Output is:

输出是:

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

回答by Chad

One possible solution is the following:

一种可能的解决方案如下:

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);

Basically store the object type in a place you know to look for later on when parsing the json. if you have multiple objects you can instantiate in a single scope the second parse method may be more appropriate. This also will account for objects in the JSON that are notCarboardBoxs.

基本上将对象类型存储在稍后解析 json 时您知道要查找的位置。如果您有多个对象,您可以在单个范围内实例化,则第二个解析方法可能更合适。这也将解释 JSON 中不是CarboardBoxs 的对象。

EditHere is a jsFiddleof this method in action.

编辑这里是这个方法在行动的jsFiddle

回答by nrabinowitz

Overall, you're correct: Javascript doesn't have any built-in way to serialize anything beyond plain objects, so going to and from JSON will not produce a particular class when you deserialize it. So you need to either work out serialization/deserialization yourself, or use a library that provides some support.

总的来说,您是对的:Javascript 没有任何内置方法来序列化普通对象之外的任何内容,因此在反序列化它时,往返 JSON 不会产生特定的类。因此,您需要自己进行序列化/反序列化,或者使用提供一些支持的库。

I personally like Backbone.jsfor this problem, as it handles serializing and deserializing quite well. You define a model class, which include a method to save its data to a server in a serialized form, and a method to deserialize it back to the model. The key design issue here is that deserializing is performed knowing the modelyou're deserializing to:

我个人喜欢Backbone.js来解决这个问题,因为它可以很好地处理序列化和反序列化。您定义了一个模型类,其中包括一个以序列化形式将其数据保存到服务器的方法,以及一个将其反序列化回模型的方法。这里的关键设计问题是反序列化是在知道您要反序列化为的模型的情况下执行

  • you either call myModel.fetch()to get data from the server based on the model id, or
  • you pass a bunch of new data to the model constructor: new Model(serializedData), or
  • you pass an array of data for multiple models to a collection that knows the model type: new ModelCollection(arrayOfSerializedData).
  • 您要么myModel.fetch()根据模型 ID调用从服务器获取数据,要么
  • 您将一堆新数据传递给模型构造函数:new Model(serializedData),或
  • 您传递的多个模型数据的阵列,它知道该模型类型的集合:new ModelCollection(arrayOfSerializedData)

What Backbone doesn't do is deal with type-casting data of an unknown type. When I've dealt with this, I've usually done something similar to @Chad's response, but using an intermediary; you could see this as a proxy model, or as a factory:

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

This still relies on a custom flag to switch types, though - I'm not sure there's any way around this.

不过,这仍然依赖于自定义标志来切换类型 - 我不确定有什么办法可以解决这个问题。