PDA

View Full Version : Object cloning function



mabello
10 Jun 2008, 1:28 PM
I have already posted my code in a Saki's post about his cloning function, but just in case someone is using my code, I prefer to create a new thread, also because my cloning function is actually different from the Saki implementation.

Goal of the extension is...clone whatever javascript object...
Here is the code:



/**
* Clone Function
*/
Ext.ux.clone = function(obj)
{
if(obj == null || typeof(obj) != 'object')
return obj;
if (Ext.isDate(obj))
return obj.clone();

var cloneArray = function(arr)
{
var len = arr.length;
var out = [];
if (len > 0)
{
for (var i = 0; i < len; ++i)
out[i] = Ext.ux.clone(arr[i]);
}
return out;

};

var c = new obj.constructor();
for (var prop in obj)
{
var p = obj[prop];
if (Ext.isArray(p))
c[prop] = cloneArray(p);
else if (typeof p == 'object')
c[prop] = Ext.ux.clone(p);
else
c[prop] = p;
}
return c;
};


Using the code


//Use it
var date = new Date();
alert(date);

var date1 = Ext.ux.clone(date);
alert(date1);

Thanks and keep up the good work with Ext

evant
11 Jun 2008, 12:00 AM
Just added a few minor tweaks to the above (copy arrays and dates using the built in cloning methods):



Ext.ux.clone = function(obj)
{
if (!obj)
return null;

var cloneArray = function(arr)
{
var len = arr.length;
var out = [];
if (len > 0)
{
for (var i = 0; i < len; ++i)
out[i] = Ext.ux.clone(arr[i]);
}
return out;

};

var c = new obj.constructor();
for (var prop in obj)
{
var p = obj[prop];
if (Ext.isDate(p))
c[prop] = p.clone();
else if (Ext.isArray(p))
c[prop] = cloneArray(p);
else if (typeof p == 'object')
c[prop] = Ext.ux.clone(p);
else
c[prop] = p;
}
return c;
};

mabello
11 Jun 2008, 12:20 AM
Dear evant,
thank you very much for your help, now I think is perfect ;)

mabello
12 Jun 2008, 3:35 PM
@evant
Another small correction, otherwise it does not work with date or string:



var date = new Date();
alert(date);
var clonedDate = Ext.ux.clone(date);
alert(clonedDate );//wrong!

var str = "string";
var clonStr = Ext.ux.clone(str);
alert(clonStr );//wrong!




Ext.ux.clone = function(obj)
{
if(obj == null || typeof(obj) != 'object')
return obj;
if (Ext.isDate(obj))
return obj.clone();

var cloneArray = function(arr)
{
var len = arr.length;
var out = [];
if (len > 0)
{
for (var i = 0; i < len; ++i)
out[i] = Ext.ux.clone(arr[i]);
}
return out;

};

var c = new obj.constructor();
for (var prop in obj)
{
var p = obj[prop];
if (Ext.isArray(p))
c[prop] = cloneArray(p);
else if (typeof p == 'object')
c[prop] = Ext.ux.clone(p);
else
c[prop] = p;
}
return c;
};

mystix
12 Jun 2008, 7:46 PM
life-saver :)

pdchapin
29 Jan 2009, 1:59 PM
This appears to fail with a simpleStore. It seems to have a problem with the line

var c = new obj.constructor();I was originally was trying to clone a complex object which contained a simpleStore and when it tried to close the store. In that case it reported that A was undefined. I then tried in the simpler situation below and it failed without returning a error.


for (i = 0; i < projectResponses.length; i++) {
dataArray[i] = [projectResponses[i]['project_id'],projectResponses[i]['project_name'],projectResponses[i]['key']];
}

pSStore = new Ext.data.SimpleStore(
{
fields: ['pID','pValue','pkey'],
data: dataArray
});

tempstore = Ext.ux.clone(pSStore);

mabello
30 Jan 2009, 1:14 AM
I'll have a look.
I hope to get back to you soon.
Thanks for pointing that out

mabello
30 Jan 2009, 1:42 AM
I figured it out.
Basically, when

var c = new obj.constructor();
is executed, you are trying to create a new store (a SimpleStore more precisely)using its constructor function.
But the constructor of the SimpleStore expects to get a cfg object as input parameter, check out the constructor:



Ext.data.SimpleStore = function(config){
Ext.data.SimpleStore.superclass.constructor.call(this, Ext.apply(config, {
reader: new Ext.data.ArrayReader({
id: config.id
},
Ext.data.Record.create(config.fields)
)
}));
};


When the constructor is called, config.id throw the exceptions since config is undefined.

My clone function works (so far) only if there is a "default" constructor which does not take an input mandatory parameter.

I would say that in the case of the SimpleStore, it would be good to insert a precondition for the constructor that checks that the config object is not null or undefined.

Anyway, I think that for "complex Ext component" the best should be to have a clone function for each of them (every component implements the "ICloneable" interface by implementing the clone method) andin my clone function check if the object to clone has its own clone implemented, so that in that case it will use the clone function of the object...

pdchapin
30 Jan 2009, 8:20 AM
Thanks for the information. Actually, I realized that I don't actually need the store in the clone so I simply added a line that skips it. This seems to work fine but now I'm getting a "too much recursion" message. I got the same thing when I tried a different clone function. I suspect that the object I'm working with is just too large for this approach.

Outliver
18 Nov 2009, 12:59 AM
It doesn't work for tree nodes, too. That's because the nodes' got their "ownerTree" and "parentNode" and stuff as attributes. So you'll get too much recursion when you call the function again

c[prop] = Ext.ux.clone(p);

Here's my approach:


/**
* Clone Function
*/
Ext.ux.clone = function (obj)
{
function c(obj)
{
for (var i in obj)
{
this[i] = obj[i];
}
}
return new c(obj);
};