Skip to main content

News

Topic: Confusing issue (Read 7849 times) previous topic - next topic

0 Members and 1 Guest are viewing this topic.
Confusing issue
Ok so as an example you have a function like this
Code: (javascript) [Select]

function fadeObject(colour, time)
{
  this.time = time;
  this.newMask = colour.red;
  this.oldMask = CreateColor(0, 0, 0, 0);
 
  this.flagged = true;
  this.destroy = false;
  this.fadeTime = time;
  this.fadeCount = 1;
  Abort(this.newMask)
  this.fadeColourDifference = {};
  this.fadeColourDifference.red = (this.newMask.red - this.oldMask.red) / this.fadeTime;
  this.fadeColourDifference.blue = (this.newMask.blue - this.oldMask.blue) / this.fadeTime;
  this.fadeColourDifference.green = (this.newMask.green - this.oldMask.green) / this.fadeTime;
  this.fadeColourDifference.alpha = (this.newMask.alpha - this.oldMask.alpha) / this.fadeTime ;
}


The Abort returns "0" just as it should, yet :
Code: (javascript) [Select]
this.fadeColourDifference.red = (this.newMask.red - this.oldMask.red) / this.fadeTime;


returns that this.newMask has no properties?

It definatly DOES have properties as if I Abort and check ANY of those properties they are there and the object itself returns as a color object???

Im trying to pass a color between a few functions including as a property in a object created within on of those functions so this is frustrating as I don't wanna use the global scope

(edit - code tags fixed ~neo)
  • Last Edit: May 13, 2013, 03:41:42 pm by N E O

Re: Confusing issue
Reply #1
Nevermind, its my cloning function elsewhere in the script. Its not copying the properties aparrently

Anyone got a clone function they would like to share (Deep cloning)

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Confusing issue
Reply #2
Here you go, took me about 2 minutes to write:

Code: (javascript) [Select]
function clone(o)
{
if (typeof o === 'object' && o !== null) {
var dolly = {};
for (var p in o) {
dolly[p] = clone(o[p]);
}
} else {
dolly = o;
}
return dolly;
}


I love JavaScript. :)
  • Last Edit: May 13, 2013, 03:20:04 pm by Lord English
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

Re: Confusing issue
Reply #3
You probably already know this, but that will die on cyclic references. Also it won't quite work correctly if you extend any native prototypes, or if you try to copy an object that that inherits from another object. Additionally, instanceof will not work on the cloned objects. I haven't tried, but it probably won't clone native Sphere objects properly, either (IIRC some of them have important non-enumerable properties).
You probably want something like this instead.

If you can be completely sure that you won't be dealing with cyclic objects and you're not cloning native objects and you're not extending native prototypes and you don't check that anything is an instanceof a constructor function, that one will work (and is nice and simple). I'd guess those assumptions are true about 90% of the time, so you should probably be OK (the only commonly cloned Sphere native is Color, which I'm pretty sure has all enumerable properties).

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Confusing issue
Reply #4
Or this, Alpha123, one can use json2 with cycles to eliminate cyclic structures:

Code: (javascript) [Select]

/**
* Serialize(obj : object);
*  - Use this to JSON an object; AND preserve the data type.
**/
function Serialize(obj)
{
    function Make(obj) {
        var o = Assert.isArray(obj) ? [] : { zztype: obj.constructor.name };
       
        for (var i in obj) {
            if (Assert.is(obj[i], "object")) o[i] = Make(obj[i]);
            else o[i] = obj[i];
        }
       
        return o;
    }
   
    if(Assert.is(obj, "object"))
        return JSON.stringify(Make(obj));
    else
        return JSON.stringify(obj);
}

/**
* Deserialize(s : string);
*  - Use this to parse a JSON object; AND restore the methods.
**/
function Deserialize(s)
{
    function Make(o) {
        var obj = [];
       
        if (!Assert.isArray(o)) {
            if (o.zztype in this) obj = new global[o.zztype]();
            else {
                Debug.log("Can't deserialize type: {?}", o.zztype, LIB_ERROR);
                return;
            }
        }
       
        for (var i in o) {
            if (Assert.is(o[i], "object")) obj[i] = Make(o[i]);
            else obj[i] = o[i];
        }
       
        if (!Assert.isArray(obj)) delete obj.zztype;
        return obj;
    }
   
    return Make(JSON.parse(s));
}

/**
* DeepClone(obj : object);
*  - generates a full, deep, and accurate copy of the object.
**/
function DeepClone(obj) {
    return Deserialize(Serialize(obj));
}


But it's not going to be lightning fast. And really, all you need is a clone for the job. If it's a simple thing that needs cloning say a point = {x: 0, y: 0 }; then you don't need a huge, fancy copier. LordEnglish's solution is fine for bigger, nested objects, and mine if you want full instanceof support and method keeping.

It doesn't clone native Sphere objects though. I'll have to have it find and add their .clone() methods.

(edit - cleaned up tags ~neo)
  • Last Edit: May 13, 2013, 04:29:19 pm by N E O
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Confusing issue
Reply #5
That's great until you want to clone something that wasn't created from a constructor function but has methods, which is a rather common situation....
I haven't tried it, but won't that not copy
Code: (javascript) [Select]
DeepClone({a: 1, b: function () { return 2; }});

correctly?

Really, just use a proper deep copy algorithm. The implementation I linked to earlier even allows registering custom copiers, so it would be really easy to extend it to copy built-in Sphere types.

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Confusing issue
Reply #6
Umm, you are right it'll lose that function. But, I mean there's only so far one will go for cloning. I'd still say to just use one that suits the need. My method just uses prototype-preserving JSON, the cloning is just an application of those two algorithms.

Well, this does the trick:
Code: (javascript) [Select]

/**
* ShallowClone(obj : object);
*  - generates a shallow copy of the object.
**/
function ShallowClone(obj) {
    var o = new global[obj.constructor.name]();
    Absorb(o, obj);
    return o;
}


But no cyclic structures :/
  • Last Edit: May 13, 2013, 05:26:26 pm by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Confusing issue
Reply #7
Here's an adaption of my earlier function that handles circular refs:
Code: (javascript) [Select]
function clone(o)
{
var clones = arguments.length >= 2 ? arguments[1] : [];
if (typeof o === 'object' && o !== null) {
for (var i = 0; i < clones.length; ++i) {
if (o === clones[i].original) {
return clones[i].dolly;
}
}
var dolly = {};
clones.push({ original: o, dolly: dolly });
for (var p in o) {
dolly[p] = clone(o[p], clones);
}
return dolly;
} else {
return o;
}
};


I'd wager that the vast majority of the time you're going to be cloning simple data objects. For that, the above is sufficient.  I see a lot of talk about preserving the cloned object's prototype chain, but really, if you have a constructor-created object that you want to clone, that object should ideally implement its own clone method.  If it doesn't, you shouldn't try to clone it yourself anyway because you can't be sure changing all its references (deep copy or not) isn't going to break something.
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Confusing issue
Reply #8

but really, if you have a constructor-created object that you want to clone, that object should ideally implement its own clone method.


+1 on that!
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Confusing issue
Reply #9
Deep copying is a solved problem guys. Either of your solutions are great for 90% of cases (the cyclic version... 90.5%), but real JavaScript deep copiers that work for 100% of cases exist. (Like I mentioned earlier, the one I linked to can even handle Sphere native objects.)


but really, if you have a constructor-created object that you want to clone, that object should ideally implement its own clone method.

I agree, actually. However, sometimes you do want to copy objects not created from constructors (object literals or Object.create'd objects are pretty common).

  • Fat Cerberus
  • [*][*][*][*][*]
  • Global Moderator
  • Sphere Developer
Re: Confusing issue
Reply #10
...and nobody caught the joke embedded in my clone() function code... tsk tsk. :D
neoSphere 5.9.2 - neoSphere engine - Cell compiler - SSj debugger
forum thread | on GitHub

  • Radnen
  • [*][*][*][*][*]
  • Senior Staff
  • Wise Warrior
Re: Confusing issue
Reply #11
Original clone!

edit: I didn't find 'dolly' as funny as the oxymoron: original clone/copy.
  • Last Edit: May 15, 2013, 03:01:53 am by Radnen
If you use code to help you code you can use less code to code. Also, I have approximate knowledge of many things.

Sphere-sfml here
Sphere Studio editor here

Re: Confusing issue
Reply #12
Dolly! :P

(To be honest, I'd only skimmed over your function the first time.)