Created
September 12, 2012 19:47
-
-
Save imbcmdth/3709419 to your computer and use it in GitHub Desktop.
Robust deep copying of objects w/ support for cycles
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var deepCopy = (function () { | |
var funcBlacklist = ['caller', 'arguments', 'prototype' ], | |
primitiveCloner = makeCloner(clonePrimitive), | |
cloneFunctions = { | |
'[object Null]': primitiveCloner, | |
'[object Undefined]': primitiveCloner, | |
'[object Number]': primitiveCloner, | |
'[object String]': primitiveCloner, | |
'[object Boolean]': primitiveCloner, | |
'[object RegExp]': makeCloner(cloneRegExp), | |
'[object Date]': makeCloner(cloneDate), | |
'[object Function]': makeRecCloner(makeCloner(cloneFunction), funcBlacklist), | |
'[object Object]': makeRecCloner(makeCloner(cloneObject)), | |
'[object Array]': makeRecCloner(makeCloner(cloneArray)) | |
}; | |
function clonePrimitive(primitive) { | |
return primitive; | |
} | |
function cloneRegExp(regexp) { | |
return RegExp(regexp); | |
} | |
function cloneDate(date) { | |
return new Date(date.getTime()); | |
} | |
function cloneFunction(fn) { | |
var copy = Function('return ' + fn.toString() + ';')(); | |
copy.prototype = Object.getPrototypeOf(fn); | |
return copy; | |
} | |
// This will not properly clone `constructed` objects | |
// because it is impossible to know what arguments the constructor | |
// was originally invoked with. | |
function cloneObject(object) { | |
return Object.create(Object.getPrototypeOf(object)); | |
} | |
function cloneArray(array) { | |
return []; | |
} | |
function makeCloner(cloneThing) { | |
return function (thing, thingStack, copyStack) { | |
var copy = cloneThing(thing); | |
thingStack.push(thing); | |
copyStack.push(copy); | |
return copy; | |
}; | |
} | |
function makeRecCloner(cloneThing, blacklist) { | |
return function (thing, thingStack, copyStack) { | |
var clone = this; | |
return Object.getOwnPropertyNames(thing). | |
filter(function (prop) { | |
return !blacklist || blacklist.indexOf(prop) === -1; | |
}). | |
reduce(function (copy, prop) { | |
var thingOffset = thingStack.indexOf(thing[prop]); | |
copy[prop] = (thingOffset === -1) ? | |
clone(thing[prop]) : | |
copyStack[thingOffset]; | |
return copy; | |
}, cloneThing(thing, thingStack, copyStack)); | |
}; | |
} | |
return function (cloneMe) { | |
var thingStack = [], | |
copyStack = []; | |
function clone(thing){ | |
var type = Object.prototype.toString.call(thing); | |
return cloneFunctions[type].call(clone, thing, thingStack, copyStack); | |
} | |
return clone(cloneMe); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment