循環参照を含むオブジェクトのディープコピー
function deepCopy(orig) { var clone = {}; return (function (orig, clone, visited, ref) { for (var k in orig) { var v = orig[k]; if (v instanceof Object) { var i = visited.indexOf(v); if (i == -1) { var o = {}; visited.push(v); ref.push(o); clone[k] = arguments.callee(v, o, visited, ref); } else { clone[k] = ref[i]; } } else { clone[k] = v; } } return clone; })(orig, clone, [orig], [clone]); } var obj = {a: 1, b: 2}; obj.self = obj; var cp = deepCopy(obj); cp.self.a = 2; console.log(cp, cp.self == cp, obj.a, cp.a); // Object a=2 b=2 self=Object true 1 2
Rubyだと、循環参照を含んでいてもMarshal.dumpがうまく動くので、
Marshal.load(Marshal.dump(obj));
で大丈夫。
JavaScriptの場合、オブジェクトを文字列化する方法として、uneval+eval、JSON.stringify+JSON.parseがある。JSONリテラルでは循環参照を含むオブジェクトを書くことはできない。unevalはFirefoxにしかないけど、Firefox用に拡張されたシャープリテラルを使って、
eval(uneval(#1={self: #1#}));
といった具合に、ディープコピーできる。