Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
179
rated 0 times [  180] [ 1]  / answers: 1 / hits: 15342  / 12 Years ago, sat, april 14, 2012, 12:00:00

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"

More From » prototype

 Answers
17

Some comments on the code:



>    if (obj instanceof Date) {
> var copy = new Date();
> copy.setTime(obj.getTime());


can be:



if (obj instanceof Date) {
var copy = new Date(obj);


and



>    if (obj instanceof Array) {


will return false if obj is an array from another global context, such as an iFrame. Consider:



     if (o && !(o.constructor.toString().indexOf(Array) == -1))

> var copy = [];
> for (var i = 0, len = obj.length; i < len; ++i) {
> copy[i] = cloneObject(obj[i]);
> }


Copying the indexes of one array to another can be done more efficiently and accurately using slice:



      var copy = obj.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 with hasOwnProperty) 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 prototype is 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 as beget) 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.


[#86244] Thursday, April 12, 2012, 12 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
malkajillc

Total Points: 652
Total Questions: 107
Total Answers: 98

Location: Finland
Member since Sat, Nov 6, 2021
3 Years ago
malkajillc questions
;