Skip to content

Commit

Permalink
simpler clone implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
James Halliday committed Feb 18, 2011
1 parent d411695 commit 6a6cb49
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 25 deletions.
43 changes: 18 additions & 25 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,31 @@ Traverse.prototype.nodes = function () {
};

Traverse.prototype.clone = function () {
// clone refObj for a properly immutable interface:
var refs = [];
var nodes = [];
var parents = [], nodes = [];

return (function clone (ref) {
if (typeof ref == 'object' && ref !== null) {
var node = Array.isArray(ref) ? [] : {};
refs.push(ref);
nodes.push(node);
return (function clone (src) {
for (var i = 0; i < parents.length; i++) {
if (parents[i] === src) {
return nodes[i];
}
}

if (typeof src === 'object' && src !== null) {
var dst = Array.isArray(src) ? [] : Object.create(src.__proto__);

Object.keys(ref).forEach(function (key) {
var i = refs.indexOf(ref[key]);
if (i >= 0) {
node[key] = nodes[i];
}
else {
node[key] = clone(ref[key]);
}

parents.push(src);
nodes.push(dst);

Object.keys(src).forEach(function (key) {
dst[key] = clone(src[key]);
});

refs.pop();
parents.pop();
nodes.pop();

// To make instanceof work:
if (!Array.isArray(ref)) node.__proto__ = ref.__proto__;

// Probably there are other attributes worth copying
return node;
return dst;
}
else {
return ref;
return src;
}
})(this.value);
};
Expand Down
16 changes: 16 additions & 0 deletions test/circular.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,19 @@ exports.circDubUpMap = function () {

assert.eql(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
};

exports.circClone = function () {
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
obj.y[2] = obj;
obj.x.push(obj.y);

var clone = Traverse.clone(obj);
assert.ok(obj !== clone);

assert.ok(clone.y[2] === clone);
assert.ok(clone.y[2] !== obj);
assert.ok(clone.x[3][2] === clone);
assert.ok(clone.x[3][2] !== obj);
assert.eql(clone.x.slice(0,3), [1,2,3]);
assert.eql(clone.y.slice(0,2), [4,5]);
};

0 comments on commit 6a6cb49

Please sign in to comment.