I am attempting to clone an object in JavaScript. I have made my own ‘class’ that has prototype functions.
My Problem: When I clone an object, the clone can’t access/call any prototype functions.
I get an error when I go to access a prototype function of the clone:
clone.render is not a function
Can you tell me how I can clone an object and keep its prototype functions
This simple JSFiddle demonstrates the error I get: http://jsfiddle.net/VHEFb/1/
function cloneObject(obj)
{
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; ++i) {
copy[i] = cloneObject(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = cloneObject(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
function MyObject(name)
{
this.name = name;
// I have arrays stored in this object also so a simple cloneNode(true) call wont copy those
// thus the need for the function cloneObject();
}
MyObject.prototype.render = function()
{
alert("Render executing: "+this.name);
}
var base = new MyObject("base");
var clone = cloneObject(base);
clone.name = "clone";
base.render();
clone.render(); // Error here: "clone.render is not a function"
Some comments on the code:
can be:
and
will return false if obj is an array from another global context, such as an iFrame. Consider:
Copying the indexes of one array to another can be done more efficiently and accurately using
slice:though you will miss any other properties that might have been added that aren’t numeric. Looping over 0 to length will add properties to the clone that don’t exist in a sparse array (e.g. elisions will become undefined members).
As for the cloning part…
In the part copying object properties, that will copy all the properties, including those on the original’s
[[Prototype]]chain, directly to the “clone” object. The only way to really “clone” an object is to set its[[Prototype]]to the same object as the original, then copy the enumerable properties on the original (filtered withhasOwnProperty) to the clone.The second part is trivial, the first part is not (in a general sense) since you can’t guarantee that an object’s constructor property references the object whose
prototypeis its[[Prototype]], nor can you guarantee that the constructor’s prototype hasn’t changed (i.e. is a different object) in the meantime.The closest you can get is to use Lasse Reichstein Nielsen’s
clone(popularised by Douglas Crockford asbeget) which makes the original object the[[Prototype]]of the clone, and then set the constructor to the same object. Though you probably still need to copy over the enumerable own properties so they mask the original’s same-named properties.So you can really only clone an object within a restricted context, you can’t do it generally. And generally that realisation leads to a design where you don’t need to generically clone objects.