javascript 如何从 JSON 恢复原始对象/类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14027168/
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
How to restore original object/type from JSON?
提问by John Little
Its easy to load JSON into an object in javascript using eval or JSON.parse.
使用 eval 或 JSON.parse 很容易将 JSON 加载到 javascript 中的对象中。
But if you have a proper "class" like function, how do you get the JSON data into it?
但是如果你有一个合适的“类”之类的函数,你如何将 JSON 数据放入其中?
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!
The crux is I need to be able to create proper Person instances from JSON, but all I can get is a dumb object. Im wondering if its possible to do something with prototypes?
关键是我需要能够从 JSON 创建适当的 Person 实例,但我所能得到的只是一个愚蠢的对象。我想知道是否可以用原型做点什么?
I dont want to have to parse each line of the JSON and assign each variable to the coresponding functions attributes, which would be too difficult. The actualy JSON and functions I have are much more complicated than the example above.
我不想解析JSON的每一行并将每个变量分配给对应的函数属性,这太困难了。我拥有的实际 JSON 和函数比上面的示例复杂得多。
I am assuming one could JSONify the functions methods into the JSON string, but as I need to keep the resultant data as small as possible this is not an option - I only want to store and load the data, not the javascript code for the methods.
我假设可以将函数方法 JSONify 转换为 JSON 字符串,但是因为我需要将结果数据保持得尽可能小,所以这不是一个选项 - 我只想存储和加载数据,而不是方法的 javascript 代码.
I also dont want to have to put the data loaded by JSON as a sub object if I can help it (but might be the only way), e.g.
如果可以的话,我也不想将 JSON 加载的数据作为子对象(但可能是唯一的方法),例如
function Person(name) {
this.data = {};
this.data.name=name;
}
var newPerson = new Person("");
newPerson.data = eval( "(" + aPersonJSON + ")" );
alert (newPerson.data.name); // Bob
Any ideas?
有任何想法吗?
回答by Sean Kinsey
You need to use a reviver
function:
您需要使用一个reviver
函数:
// 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
No other way really...
真的没有别的办法...
回答by david
Many frameworks provide an 'extend' function that will copy fields over from one object to another. You can combine this with JSON.parse to do what you want.
许多框架提供了“扩展”功能,可以将字段从一个对象复制到另一个对象。你可以将它与 JSON.parse 结合起来做你想做的事。
newPerson = new Person();
_.extend(newPerson, JSON.parse(aPersonJSON));
If you don't want to include something like underscore you can always copy over just the extend function or write your own.
如果您不想包含下划线之类的内容,您可以随时复制扩展函数或编写自己的函数。
Coffeescript example because I was bored:
Coffeescript 示例,因为我很无聊:
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()
回答by GTCrais
A little late to the party, but this might help someone. This is how I've solved it, ES6 syntax:
聚会有点晚了,但这可能会对某人有所帮助。这就是我解决它的方法,ES6 语法:
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);
Your page should be restored as an object of class Page
, with array containing 2 objects of class PageSection
. Recursion works all the way to the last object regardless of depth.
您的页面应该恢复为类对象Page
,数组包含 2 个类对象PageSection
。无论深度如何,递归都会一直工作到最后一个对象。
@Sean Kinsey's answer helped me get to my solution.
@Sean Kinsey 的回答帮助我找到了解决方案。
回答by Qpirate
Easiest way is to use JSON.parse
to parse your string then pass the object to the function. JSON.parse
is part of the json2 library online.
最简单的方法是使用JSON.parse
解析字符串然后将对象传递给函数。JSON.parse
是 json2 在线库的一部分。
回答by Roman Riesen
Just in case someone needs it, here is a pure javascript extend function (this would obviously belong into an object definition).
以防万一有人需要它,这里有一个纯 javascript 扩展函数(这显然属于对象定义)。
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])
}
}
Please don't forget to remove the console.log
:P
请不要忘记删除console.log
:P
回答by Omiga
I;m not too much into this, but aPerson.addAddress should not work, why not assigning into object directly ?
我不太喜欢这个,但是 aPerson.addAddress 不应该工作,为什么不直接分配给对象?
aPerson.address.push(someAddress);
alert(aPerson.address); // alert [object object]