<!DOCTYPE html>
<script>
'use strict'
Object.isObject = Object.isObject || function isObject(obj) { return !!obj && typeof obj == 'object' }
function byXJSON(xjson) {
var refs = JSON.parse(xjson)
var vals = refs.map(function (ref) {
return typeof ref == 'object' ? {} : ref
})
refs.reduceRight(function (goo ,ref, id) {
if (!Object.isObject(ref)) return
Object.keys(ref).forEach(function (key) {
vals[id][key] = vals[ref[key]]
})
}, void 0)
return vals[0]
}
function toXJSON(obj, full) {
var refs = []
var vals = []
conv(obj, 0)
function conv(obj, id) {
vals[id] = obj
var ref = refs[id] = {}
var keys = full ? Object.getOwnPropertyNames(obj) : Object.keys(obj)
keys.forEach(function (key) {
var val = obj[key]
var id = vals.indexOf(val)
if (id != -1) {
ref[key] = id
return
}
id = vals.length
ref[key] = id
if (Object.isObject(val)) {
conv(val, id)
} else {
vals[id] = val
refs[id] = val
}
})
}
chkCir(refs) //循環参照をチェック
return JSON.stringify(refs)
}
function chkCir(refs) {
refs.forEach(function (ref, i) {
if (!Object.isObject(ref)) return
Object.keys(ref).forEach(function (key) {
if (Object.isObject(ref[key])) console.log('chkerr', i, key)
})
})
}
function test(id, obj, full) {
console.group('test ' + id)
var xjson = toXJSON(obj, full)
var xobj = byXJSON(xjson)
console.log(xjson)
console.dir(xobj)
console.dir(obj)
console.groupEnd('test ' + id)
}
function testing() {
var obj1 = {
a: {
b: {
c: {},
d: 'xyz',
e: {}
},
f: 123,
},
g: [0,1,2,3]
}
obj1.a.b.c = obj1
obj1.a.b.e = obj1.a
test(1, obj1)
test(2, Math, true)
test(3, window)
}
window.onload = testing
</script>
PCFET0NUWVBFIGh0bWw+CjxzY3JpcHQ+Cid1c2Ugc3RyaWN0JwoKT2JqZWN0LmlzT2JqZWN0ID0gT2JqZWN0LmlzT2JqZWN0IHx8IGZ1bmN0aW9uIGlzT2JqZWN0KG9iaikgeyByZXR1cm4gISFvYmogJiYgdHlwZW9mIG9iaiA9PSAnb2JqZWN0JyB9CgoKCmZ1bmN0aW9uIGJ5WEpTT04oeGpzb24pIHsKCgoJdmFyIHJlZnMgPSBKU09OLnBhcnNlKHhqc29uKQoKCgl2YXIgdmFscyA9IHJlZnMubWFwKGZ1bmN0aW9uIChyZWYpIHsKCQlyZXR1cm4gdHlwZW9mIHJlZiA9PSAnb2JqZWN0JyA/IHt9IDogcmVmCgl9KQoKCXJlZnMucmVkdWNlUmlnaHQoZnVuY3Rpb24gKGdvbyAscmVmLCBpZCkgewoJCWlmICghT2JqZWN0LmlzT2JqZWN0KHJlZikpIHJldHVybgoJCU9iamVjdC5rZXlzKHJlZikuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7CgkJCXZhbHNbaWRdW2tleV0gPSB2YWxzW3JlZltrZXldXQoJCX0pCgl9LCB2b2lkIDApCgoJcmV0dXJuIHZhbHNbMF0KCn0KCgoKZnVuY3Rpb24gdG9YSlNPTihvYmosIGZ1bGwpIHsKCgl2YXIgcmVmcyA9IFtdCgl2YXIgdmFscyA9IFtdCgoJY29udihvYmosIDApCgoKCWZ1bmN0aW9uIGNvbnYob2JqLCBpZCkgewoKCQl2YWxzW2lkXSA9IG9iagoJCXZhciByZWYgPSByZWZzW2lkXSA9IHt9CgkJdmFyIGtleXMgPSBmdWxsID8gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob2JqKSA6IE9iamVjdC5rZXlzKG9iaikKCgkJa2V5cy5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHsKCQkJdmFyIHZhbCA9IG9ialtrZXldCgoJCQl2YXIgaWQgPSB2YWxzLmluZGV4T2YodmFsKQoKCQkJaWYgKGlkICE9IC0xKSB7CgkJCQlyZWZba2V5XSA9IGlkCgkJCQlyZXR1cm4KCQkJfQoKCQkJaWQgPSB2YWxzLmxlbmd0aAoJCQlyZWZba2V5XSA9IGlkCgoJCQlpZiAoT2JqZWN0LmlzT2JqZWN0KHZhbCkpIHsKCQkJCWNvbnYodmFsLCBpZCkKCQkJfSBlbHNlIHsKCQkJCXZhbHNbaWRdID0gdmFsCgkJCQlyZWZzW2lkXSA9IHZhbAoJCQl9CgoJCX0pCgoJfQoKCgljaGtDaXIocmVmcykgLy/lvqrnkrDlj4LnhafjgpLjg4Hjgqfjg4Pjgq8KCglyZXR1cm4gSlNPTi5zdHJpbmdpZnkocmVmcykKCn0KCgoKZnVuY3Rpb24gY2hrQ2lyKHJlZnMpIHsKCXJlZnMuZm9yRWFjaChmdW5jdGlvbiAocmVmLCBpKSB7CgkJaWYgKCFPYmplY3QuaXNPYmplY3QocmVmKSkgcmV0dXJuCgkJT2JqZWN0LmtleXMocmVmKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHsKCQkJaWYgKE9iamVjdC5pc09iamVjdChyZWZba2V5XSkpIGNvbnNvbGUubG9nKCdjaGtlcnInLCBpLCBrZXkpCgkJfSkKCX0pCn0KCgoKZnVuY3Rpb24gdGVzdChpZCwgb2JqLCBmdWxsKSB7CgoJY29uc29sZS5ncm91cCgndGVzdCAnICsgaWQpCgl2YXIgeGpzb24gPSB0b1hKU09OKG9iaiwgZnVsbCkKCXZhciB4b2JqICA9IGJ5WEpTT04oeGpzb24pCgljb25zb2xlLmxvZyh4anNvbikKCWNvbnNvbGUuZGlyKHhvYmopCgljb25zb2xlLmRpcihvYmopCgljb25zb2xlLmdyb3VwRW5kKCd0ZXN0ICcgKyBpZCkKCn0KCgpmdW5jdGlvbiB0ZXN0aW5nKCkgewoJdmFyIG9iajEgPSB7CgkJYTogewoJCQliOiB7CgkJCQljOiB7fSwKCQkJCWQ6ICd4eXonLAoJCQkJZToge30KCQkJfSwKCQkJZjogMTIzLAoJCX0sCgkJZzogWzAsMSwyLDNdIAoJfQoKCW9iajEuYS5iLmMgPSBvYmoxCglvYmoxLmEuYi5lID0gb2JqMS5hCgoKCXRlc3QoMSwgb2JqMSkKCXRlc3QoMiwgTWF0aCwgdHJ1ZSkKCXRlc3QoMywgd2luZG93KQoKfQoKCndpbmRvdy5vbmxvYWQgPSB0ZXN0aW5nCgo8L3NjcmlwdD4=