如何将inheritance的对象string化为JSON?

当使用JSON.stringify()时,json2.js似乎忽略父对象的成员。 例:

require('./json2.js'); function WorldObject(type) { this.position = 4; } function Actor(val) { this.someVal = 50; } Actor.prototype = new WorldObject(); var a = new Actor(2); console.log(a.position); console.log(JSON.stringify(a)); 

输出是:

 4 {"someVal":50} 

我期望这个输出:

 4 {"position":0, "someVal":50} 

那么就是这样, JSON.stringify不保留对象的任何非拥有的属性。 您可以在这里看看关于其他缺点和可能的解决方法的有趣讨论。

另外请注意,作者不仅logging了这些问题,还写了一个名为HydrateJS的库,可以帮助你。

这个问题比起初看起来要深一点。 即使a真正的string到{"position":0, "someVal":50} ,然后parsing它将创build一个对象具有所需的属性,但既不是一个Actor的实例,也没有原型链接WorldObject(毕竟,parsing方法没有这个信息,所以它不可能以这种方式恢复)。

为了保持原型链,聪明的技巧是必要的(像HydrateJS中使用的那些)。 如果这不是你想要的,也许你只需要在对其进行string化之前将对象“变平”。 要做到这一点,你可以例如迭代对象的所有属性,而不pipe它们是否是自己的,并重新赋值(这将确保它们在对象本身上定义,而不是从原型inheritance)。

 function flatten(obj) { var result = Object.create(obj); for(var key in result) { result[key] = result[key]; } return result; } 

函数写入的方式不会改变原始对象。 所以使用

 console.log(JSON.stringify(flatten(a))); 

你会得到你想要的输出和a将保持不变。

另一种select是在要序列化的对象原型中定义一个toJSON方法:

 function Test(){} Test.prototype = { someProperty: "some value", toJSON: function() { var tmp = {}; for(var key in this) { if(typeof this[key] !== 'function') tmp[key] = this[key]; } return tmp; } }; var t = new Test; JSON.stringify(t); // returns "{"someProperty" : "some value"}" 

这是因为JSON.stringify在尝试本地序列化之前在它接收的对象中searchtoJSON方法。

检查这个小提琴: http : //jsfiddle.net/AEGYG/

你可以使用这个函数平坦化对象:

 function flatStringify(x) { for(var i in x) { if(!x.hasOwnProperty(i)) { // weird as it might seem, this actually does the trick! - adds parent property to self x[i] = x[i]; } } return JSON.stringify(x); } 

尽pipe一般的flatten方法是有效的,但迄今为止发布的其他答案中的片段对于不可修改的属性不起作用,例如如果原型已经被冻结 。 为了处理这种情况,你需要创build一个新的对象,并为这个新的对象分配属性。 既然你只是把结果对象串起来,对象标识和其他JavaScript内部可能并不重要,所以返回一个新的对象是完全正确的。 这种方法也可以说比将一个对象的属性重新分配给自己更可读,因为它看起来不像一个无操作:

 function flatten(obj) { var ret = {}; for (var i in obj) { ret[i] = obj[i]; } return ret; } 

这里是他的答案中包含的@TomasVana片段的recursion版本,以防在对象树的多个层次中存在inheritance:

 var flatten = function(obj) { if (obj === null) { return null; } if (Array.isArray(obj)) { var newObj = []; for (var i = 0; i < obj.length; i++) { if (typeof obj[i] === 'object') { newObj.push(flatten(obj[i])); } else { newObj.push(obj[i]); } } return newObj; } var result = Object.create(obj); for(var key in result) { if (typeof result[key] === 'object') { result[key] = flatten(result[key]); } else { result[key] = result[key]; } } return result; } 

它将数组保存为数组。 以同样的方式调用它:

 console.log(JSON.stringify(flatten(visualDataViews)));