Skip to content

Instantly share code, notes, and snippets.

@lxyd
Forked from 140bytes/LICENSE.txt
Created April 12, 2012 18:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lxyd/2369704 to your computer and use it in GitHub Desktop.
Save lxyd/2369704 to your computer and use it in GitHub Desktop.
Recursively clones plain hashes and arrays (but not Dates or wrappers like Boolean(), String(), Number()). Handles one-level circular references

Deep clone for plain hashes and arrays

Clones plain js hashes and arrays recursively. But ignores Dates and object Wrappers like Boolean(), Number() etc.

Tested in IE8, Chromium, Firefox, Opera and on Android.

Handles circular references (loops of the length 1).

If you want a more powerfull deepcloner (not fitting in 140 bytes though), consider using this one: https://gist.github.com/0d3e6ce689e76105f3ef

function c(o,i,r){ // only "o" is used as an argument, r and i are used as mere local variables. "r" MUST be undefined
if(o && typeof o=="object") { // clone "o" only if it is an "object" and is not null
r = o instanceof Array ? [] : {}; // use "instanceof" instead of Array.isArray() to support IE8
for(i in o)
o.hasOwnProperty(i)? // "condition?action:0" saves us a single byte (compare to "if(condition)action")
// recursive cloning goes here:
r[i] = o[i]===o ? r : c(o[i]) // if "o[i]" is "o" - we have a primitive 1-length loop. Hanlde it
:0 // end of the "condition?action:0" statement
}
return r||o // if r was assigned to {} or [] then return r. Otherwise return the original object
} // when all spaces and comments are removed this function is exactly 140 bytes!
function c(o,i,r){if(o&&typeof o=="object"){r=o instanceof Array?[]:{};for(i in o)o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0}return r||o}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2012 lxyd <https://github.com/lxyd>, TheShock <https://github.com/theshock>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "planeObjectDeepCloner",
"description": "Recursively clones plain hashes and arrays (but not Dates or wrappers like Boolean(), String(), Number()). Handles one-level circular references.",
"keywords": [
"clone",
"object",
"array"
]
}
<!DOCTYPE html>
<title>Deep Cloner</title>
<script>
function c(o,i,r){if(o&&typeof o=="object"){r=o instanceof Array?[]:{};for(i in o)o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0}return r||o}
var x = {
a: [
{a:0, b:null, c:[1,2,"foo"]},
1,
null
],
b: {
a:{},
b:null,
c:[1,2,3]
}
};
x.c = x; // circular reference (1-length loop)
var y = c(x);
document.write('Just after cloning<br/>');
document.write('x.c === x: ' + (x.c === x) + '<br/>');
document.write('y.c === y: ' + (y.c === y) + '<br/>');
document.write('x.a[0].c[2] == ' + x.a[0].c[2] + '<br/>');
document.write('y.a[0].c[2] == ' + y.a[0].c[2] + '<br/>');
x.a[0].c[2] = "bar";
document.write('<br/>After assiginig x.a[0].c[2] = "bar"<br/>');
document.write('x.a[0].c[2] == ' + x.a[0].c[2] + '<br/>');
document.write('y.a[0].c[2] == ' + y.a[0].c[2] + '<br/>');
</script>
@xpansive
Copy link

Save some bytes by using o.pop instead of o instanceof Array (from the Byte-saving Techniques page on the wiki)

function c(o,i,r){if(typeof o=="object"){r=o.pop?[]:{};for(i in o)o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0}return r||o}

@lxyd
Copy link
Author

lxyd commented Apr 13, 2012

But what if we have a property "pop" in an Object? I don't think this is a good idea...
UPD: your variant also fails on nulls (typeof null == "object" too, so o.pop and o.hasOwnProperty will fail)

@atk
Copy link

atk commented Apr 13, 2012

instanceof is another bad idea (though not too bad). A more secure isArray method can be found in https://gist.github.com/1034882 - but that's probably too long to use here. I would suggest the following solution, but alas, it is 16bytes too long:

function c(o,i,r){r=/[AO]/.exec({}.toString.call(o));if(r&&''+o!==o){r=r[0]=='A'?[]:{};for(i in o)o.hasOwnProperty(i)?r[i]=o[i]===o?r:c(o[i]):0}return r||o}

@lxyd
Copy link
Author

lxyd commented Apr 13, 2012

isArray is not too long, but it does not work in IE8 unfortunately.

@williammalo
Copy link

Since arrays and objects are almost the same thing, would it be possible to skip the check?

@lxyd
Copy link
Author

lxyd commented Apr 13, 2012

Not because after cloning array I want to have an array and not an object with some integer keys :)
The difference is: adding elements won't change length, there will not be any push/pop properties etc.

@williammalo
Copy link

That makes perfect sense!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment