我的愿望是将给定对象编码为 JSON 的“安全”方式。这是用于记录 Node.js 中的任何抽象对象,但也可以应用于其他需求。我的研究将我指向 Node 中的 util.inspect,但这不是有效的 JSON,我希望拥有有效的 JSON,以便我以后可以重新补充水分。因为某些 Error 实例可能存在递归问题,所以我需要限制响应。此外,在某些情况下,对对象的前向和后向引用也可能是一个问题,所以我想避免重复的条目。
问问题
1270 次
2 回答
0
新答案
今天,如果有人在看这个,我会使用fclone,它在这一点上比我原来的要彻底得多。
原答案:
我在下面回答我自己的问题,因为想出一个可行的解决方案有点困难。这是我找到的一些解决方案的组合,并且似乎效果很好。
/* lib/clone-safe.js
* provides a method for creating a clone of an object without redundant object references, and protected from recursion.
* The cloned value *should* always be safe for JSON.stringify(cloneSafe(myobj))
**/
(function(){
var undef; //intentionally undefined value
function cloneSafe(obj,depth){
var refs = []; //reference to cloned objects
depth = +depth > 0 && +depth || 6; //max recursion level
var layerNumber = 0; //current layer being checked
var ret = clone(obj); //start cloning
//cleanup reference checks
while(refs.length) {
delete (refs.shift()).___copied;
}
//return the result
return ret;
//recursive clone method
function clone(obj) {
if (typeof obj == "function") return undef; //no function replication
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
//max recursion reached
if (++layerNumber >= depth) {
layerNumber--;
return undef;
}
//handle circular and duplicate references
if (obj.___copied) return undef; //already included
obj.___copied = true;
refs.push(obj);
var copy = {};
//export prototype
var m = obj.constructor && obj.constructor.toString().match(/function\s+([^\(]+)/);
if (m && m[1]) copy._prototype = m[1];
//get expected properties from any error
if (obj instanceof Error) {
copy.message = obj.message || "Error";
if (obj.stack) copy.stack = obj.stack;
if (obj.number) copy.number = obj.number;
if (obj.description) copy.description = obj.description;
if (obj.name) copy.name = obj.name;
}
for (var attr in obj) {
if (attr == "___copied") continue;
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
if (obj.prototype) {
for (var attr in obj.prototype) {
if (obj.prototype.hasOwnProperty(attr) && typeof obj.prototype[attr] !== 'function') copy[attr] = clone(obj.prototype[attr]);
delete obj.prototype[attr].___copied; //allow prototypes to be re-scanned
}
}
layerNumber--;
return copy;
}
//throw new Error("Unable to copy obj! Its type isn't supported.");
console.log("Unable to copy obj! Unsupported type: %s", typeof obj);
return undef; //unable to clone the object in question
}
}
// AMD / RequireJS
if (typeof define === "function" && define.amd) {
define("clone-safe",[],function(){ return cloneSafe; });
}
// Node.js / CommonJS
else if (typeof module !== "undefined" && module.exports) {
module.exports = cloneSafe;
}
// browser/script include
else {
//provide a method for reverting global binding
var root = this; //global on the server, window in the browser.
var previousCloneSafe = root.cloneSafe; //backreference
cloneSafe.noConflict = function(){
root.cloneSafe = previousCloneSafe;
return cloneSafe;
};
//bind to the global object
root.cloneSafe = cloneSafe;
}
}());
有一些额外的逻辑用于处理错误的对象,并确保从所述错误和给定对象的原型中获取必要的数据。响应中明确忽略了函数。当递归太深时,它将返回给定对象的未定义。
于 2012-11-27T22:49:51.990 回答
0
有一个本机 javascript JSON 对象,带有一个 stringify 方法,我认为这是你需要的:http ://www.javascripture.com/JSON#stringify
于 2012-11-29T14:24:18.490 回答