好吧,我认为这会做到。我修改了 Crockford 的cycle.js来处理 Json.NET 使用的参考格式。而且因为 TypeScript 是一种比 JavaScript 更好的语言,所以我用 TS 重写了它。我当然不发誓它没有错误(如果有人指出它们,我会尝试修复它们),但它似乎可以处理我迄今为止抛出的复杂对象图。
export function retrocycle(obj: any): void {
var catalog: any[] = [];
catalogObject(obj, catalog);
resolveReferences(obj, catalog);
}
function catalogObject(obj, catalog: any[]):void {
// The catalogObject function walks recursively through an object graph
// looking for $id properties. When it finds an object with that property, then
// it adds it to the catalog under that key.
var i: number;
if (obj && typeof obj === 'object') {
var id:string = obj.$id;
if (typeof id === 'string') {
catalog[id] = obj;
}
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
catalogObject(obj[i], catalog);
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
catalogObject(obj[name], catalog);
}
}
}
}
}
function resolveReferences(obj: any, catalog: any[]) {
// The resolveReferences function walks recursively through the object looking for $ref
// properties. When it finds one that has a value that is an id, then it
// replaces the $ref object with a reference to the object that is found in the catalog under
// that id.
var i:number, item:any, name:string, id:string;
if (obj && typeof obj === 'object') {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
item = obj[i];
if (item && typeof item === 'object') {
id = item.$ref;
if (typeof id === 'string') {
obj[i] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
item = obj[name];
if (item) {
id = item.$ref;
if (typeof id === 'string') {
obj[name] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
}
}
}
}
和等效的JS:
function retrocycle(obj) {
var catalog = [];
catalogObject(obj, catalog);
resolveReferences(obj, catalog);
}
function catalogObject(obj, catalog) {
var i;
if (obj && typeof obj === 'object') {
var id = obj.$id;
if (typeof id === 'string') {
catalog[id] = obj;
}
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
catalogObject(obj[i], catalog);
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
catalogObject(obj[name], catalog);
}
}
}
}
}
function resolveReferences(obj, catalog) {
var i, item, name, id;
if (obj && typeof obj === 'object') {
if (Object.prototype.toString.apply(obj) === '[object Array]') {
for (i = 0; i < obj.length; i += 1) {
item = obj[i];
if (item && typeof item === 'object') {
id = item.$ref;
if (typeof id === 'string') {
obj[i] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
} else {
for (name in obj) {
if (typeof obj[name] === 'object') {
item = obj[name];
if (item) {
id = item.$ref;
if (typeof id === 'string') {
obj[name] = catalog[id];
} else {
resolveReferences(item, catalog);
}
}
}
}
}
}
}
你使用它有点像这样(假设你已经连接了 SignalR 集线器):
$.connection.roomHub.server.joinRoom()
.done(function(room) {
retrocycle(room);
});
我还在 BitBucket 上为它创建了一个又快又脏的小存储库:https://bitbucket.org/smithkl42/jsonnetdecycle。