True use-cases for deep-cloning are actually pretty rare.

When bumping into such an issue, it's usually a good idea to look for
a better coding pattern rather than to add complexity, augment memory
consumption and worsen the performance by bringing out the big guns.

I'm not sure what you are attempting to do here, but there's most
certainly a better way of doing it without needing deep-cloning.

Just my two-cents.

Best,

Tobie





On Oct 8, 2:05 pm, "T.J. Crowder" <[EMAIL PROTECTED]> wrote:
> Hi,
>
> Object.clone is documented as being a shallow 
> copy:http://www.prototypejs.org/api/object/clone
>
> "Deep" cloning is more complicated than it seems at first.  A naive
> version would be along these lines:
>
> Object.extend(Object, {
>     deepClone: function(source) {
>         var result;
>         var property;
>         var val;
>
>         result = {};
>         for (property in source)
>         {
>             val = source[property];
>             if (typeof val == "object" && !Object.isFunction(val))
>             {
>                 result[property] = Object.deepClone(val);
>             }
>             else
>             {
>                 result[property] = val;
>             }
>         }
>         return result;
>     }
>
> });
>
> Caveat: I'm not at all sure "typeof val == 'object' && !
> Object.isFunction(val)" is an adequate check for whether we should
> clone the property.
>
> BUT, note that that does NOT correctly handle the full object graph.
> Consider:
>
>     var a, thing;
>
>     thing = { name: 'original' };
>     a = {};
>     a.first = thing;
>     a.second = thing;
>
>     a.first.name = 'changed';
>
> At this point, a.first.name and a.second.name both have the value
> 'changed'.  But if you used the deepClone above before changing it:
>
>     var a, thing;
>
>     thing = { name: 'original' };
>     a = {};
>     a.first = thing;
>     a.second = thing;
>
>     a = Object.deepClone(a); // <= ADDED THIS
>
>     a.first.name = 'changed';
>
> ...then a.first.name is 'changed' but a.second.name is 'original'.
> The "deep" clone is not a correct clone, because it didn't recognise
> that two properties referenced the same instance.
>
> It gets even worse if the object refers to itself, as the deepClone
> function above would infinitely recurse.
>
> Handling the full graph correctly would require that during a
> particular cloning operation, you maintained a bag of cloned objects
> keyed by *identity* (===) and reused the clones if you'd already
> cloned them in the past.  Something like this:
>
> (On pastie:http://pastie.org/287641)
> * * * * * *
> /**
>  * A very quick-and-dirty bag for having values associated with  * a
> key that's compared by
>  * identity (===)
>  */
> var SlowIdentityBag = Class.create({
>
>     /**
>      * Create an empty bag.
>      */
>     initialize: function() {
>         this.items = [];
>     },
>
>     /**
>      * Get an entry from the bag for the given key.
>      *
>      * @param   key     The key to search for
>      * @return  the associated value, or undefined if not found
>      */
>     get: function(key) {
>         var index;
>         var entry;
>
>         for (index = this.items.length - 1; index >= 0; --index)
>         {
>             entry = this.items[index];
>             if (entry.key === key)
>             {
>                 return entry.val;
>             }
>         }
>
>         return undefined;
>     },
>
>     /**
>      * Put the given value in the bag with the given key.
>      *
>      * @param   key     Take a wild guess
>      * @param   val     See above
>      */
>     put: function(key, val) {
>
>         this.items.push({ key: key, val: val});
>     }
>
> });
>
> Object.extend(Object, {
>     /**
>      * Deeply clone an object, preserving the object graph by only
> cloning each object once and
>      * reusing it if necessary.
>      *
>      * @param   source              The source object to clone
>      * @param   clonesByIdentity    Usually omitted; if given, a
> SlowIdentityBag containing
>      *                              previously-cloned objects to reuse
> keyed by the originals.
>      *                              MUST NOT contain 'source'.
>      */
>     deepClone: function(source, clonesByIdentity) {
>         var result;
>         var property;
>         var val;
>
>         // A blank result object
>         result = {};
>
>         // Usually we create this unless we're calling ourselves
>         if (!clonesByIdentity)
>         {
>             clonesByIdentity = new SlowIdentityBag();
>         }
>
>         // The source may be self-referential, so remember the
> instance
>         // we're cloning it to at the outset
>         clonesByIdentity.put(source, result);
>
>         // Process the properties
>         for (property in source)
>         {
>             val = source[property];
>             if (typeof val == "object" && !Object.isFunction(val))
>             {
>                 // Something we should clone, if we haven't already.
>                 // (That check is probably not adequate.)
>                 // Grab it or clone it.  Note that deepClone will
>                 // add it to the bag.
>                 val = clonesByIdentity.get(val) ||
> Object.deepClone(val, clonesByIdentity);
>             }
>             result[property] = val;
>         }
>         return result;
>     }});
>
> * * * * * *
>
> Caveats on that:
>
> 1. This is very much off-the-cuff.
> 2. Same caveat as earlier about the check for whether to clone the
> object.
> 3. I can't imagine it's all that fast.  Offhand I couldn't think of a
> faster way to do the SlowIdentityBag; anyone have a l33t idea there?
>
> FWIW,
> --
> T.J. Crowder
> tj / crowder software / com
>
> On Oct 8, 4:18 am, buda <[EMAIL PROTECTED]> wrote:
>
> > I have an object
>
> > var obj = {
> >   info: {
> >     section:{
> >       CountryCities:{
> >          filter: {
> >             CountryID: 'MyCountry'
> >          }
> >       }
> >     }
> >   }
>
> > }
>
> > var arg = Object.clone(obj);
> > arg.info.section.CountryCities.CountryID = '100';
>
> > or
>
> > var arg = Object.extend({}, obj);
> > arg.info.section.CountryCities.CountryID = '100';
>
> > do the same =>
> > arg.info.section.CountryCities.CountryID =
> > obj.info.section.CountryCities.CountryID = 100
>
> > but I need an independent copy of an obj in arg!!!!!
>
> > How could I do it?
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Prototype & script.aculo.us" group.
To post to this group, send email to prototype-scriptaculous@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to