1

SOLVED - This example code worked, so I compared it to the non-working I had and found a discrepancy.

In my code, the one that did not work, when declaring the color array I forgot to add a "var" before it.

m_color = [];
m_color[0] = 255;
m_color[1] = 255;
m_color[2] = 255;
m_color[3] = 255;

instead of:

var m_color = [];
m_color[0] = 255;
m_color[1] = 255;
m_color[2] = 255;
m_color[3] = 255;

That's it. No error was generated and I guess it created it as a global array shared by all the particles.

Thanks for the answers everyone. I will use them to write better javascript code.

Old question (which is no longer relevant) is below:


I have this crazy issue with javascript arrays scope.

I have a class Particle:

function ParticleClass()
{
    var m_color = [];
    m_color[0] = 255;
    m_color[1] = 255;
    m_color[2] = 255;
    m_color[3] = 255;

    var m_red = 255;
    var m_green = 255;
    var m_blue = 255;

    this.SetRandomColorRGB = SetRandomColorRGB;
    this.SetRandomColorArray = SetRandomColorArray;
    this.DrawParticleRGB = DrawParticleRGB;
    this.DrawParticleArray = DrawParticleArray;

    function SetRandomColorRGB()
    {
        m_red = Math.floor( Math.random() * 255 );
        m_green = Math.floor( Math.random() * 255 );
        m_blue = Math.floor( Math.random() * 255 );
    }

    function SetRandomColorArray()
    {
        m_color[0] = Math.floor( Math.random() * 255 );
        m_color[1] = Math.floor( Math.random() * 255 );
        m_color[2] = Math.floor( Math.random() * 255 );
    }

    function DrawParticleRGB( ctx )
    {
        // I draw the particle using m_red, m_green and m_blue.
    }

    function DrawParticleArray( ctx )
    {
        // I draw the particle using m_color[0], m_color[1], m_color[2]
    }
}

I then create an array of ParticleClass particles and draw them.

If I create a bunch of particles and try to draw them on the screen, SetRandomColorRGB and DrawParticleRGB works great. Each particle has a different color.

If I use SetRandomColorArray and DrawParticleArray, all the particles have the same color. Each time a new particle is created, all the particles change to the last color SetRandomColorArray picked.

It looks to me that arrays share memory, whereas other variables do not. Is this true? Is this a quirk of Javascript? Is something else going on?

Thanks.

4
  • 1
    This shouldn't happen and I'm pretty sure it doesn't. Each particle should have a different array. Would you provide a working demo of your code on jsfiddle.net so that we may know exactly what's going wrong? Commented May 23, 2013 at 2:45
  • 1
    Are you sure it is not throwing any error? this.DrawParticleRGB = DrawParticleRGB; should n't it be this.DrawParticleRGB = DrawParticleWithRGB; Commented May 23, 2013 at 2:46
  • SetRandomColorRGB() and SetRandomColorArray() do the exact same thing, minus the location of the assignment. Personally, I would add this.m_red, etc. inside of the functions, but that's a style choice. Your issue must be inside your draw functions, unless you have some error in your code (use some kind of debugger to catch any warnings or errors). Commented May 23, 2013 at 3:03
  • This is not the exact code. My code has more stuff in it so I wrote this simple version. That's why the function name was wrong. I'll try to get a jsfiddle example up. Commented May 23, 2013 at 3:14

3 Answers 3

1

The variable's scope is within function ParticleClass(). So variables in functions defined in this space will share the scope with its parent..

This is why sometimes you see this pattern in Javascript -

var self = this;
$('.someClass').each(function(i) {
   // function is defined as a closure
   // but it shares its scope with its parent so it can see self and access the parent's  
   // pointer to this.
});

Why don't you use prototype to define to the functions...

E.g..

var myClass = function() {
  this.stuff = 1;
}
myClass.prototype.myFunc = function() {
  // Do Something..
  this.stuff += 5;
}

// Then create instances of your class with
var i = new MyClass();

This will get you the namespace you want...

Here's an example: http://jsfiddle.net/RvCgJ/

Sign up to request clarification or add additional context in comments.

Comments

1

There's no problem with the code you posted, but having said that, you're making life more difficult by doing it this way; it's better to make proper use of prototypes:

function ParticleClass()
{
    this.m_color = [255, 255, 255, 255];

    this.m_red = 255;
    this.m_green = 255;
    this.m_blue = 255;
}

(function(p) {

p.SetRandomColorRGB = function () {
        this.m_red = Math.floor( Math.random() * 255 );
        this.m_green = Math.floor( Math.random() * 255 );
        this.m_blue = Math.floor( Math.random() * 255 );
}

p.SetRandomColorArray = function () {
        this.m_color[0] = Math.floor( Math.random() * 255 );
        this.m_color[1] = Math.floor( Math.random() * 255 );
        this.m_color[2] = Math.floor( Math.random() * 255 );
}

p.DrawParticleRGB = function( ctx ) {
        // I draw the particle using m_red, m_green and m_blue.
}

p.DrawParticleArray = function( ctx )
{
        // I draw the particle using m_color[0], m_color[1], m_color[2]
}

}(ParticleClass.prototype);

Comments

1

here... this may help explain why it is happening :

var data             = {};               // create a  data object 
data.string          = "hey society";    // Add a string value property
data.num             = 0;                // Add a integer value property
data.arr             = [0,1,2];          // Add an array property
data.date            = new Date();       // Add an object property

                     // here is where the fun starts! 

// Create a var for string property

var sString          = data.string;      // sets to "hey society", as expected.. cool
data.string          = "changed"         // change the value and the compare :
data.string         == sString           // returns false, the values are different

                      // same happens for a number.

// Now lets copy this array
var oArr             = data.arr;         // (seeing the comment pattern? XD)
data.arr             .push(3);           // and modify it.
data.arr            == oArr              // should be false? Nope. returns true.
                                         // arrays are passed by reference.

var oDate            = data.date           // what about objects?       
data.date            .setHours(0);         // modify the variable and
oDate.getTime()     == data.date.getTime() // it returns true, too!

                      // so, how do we fix the array problem?

// right in front of yer nose
var oArrFix          = data.arr.splice(0) // get a new array based on 
data.arr             .push(4)             // an unmodified version of the original
data.arr            == oArrFix            // false.. huh..

                     // How do we use this as a fix

data.arr["changed"] == false;

oArrFix              = ChangeOriginalArray( data.arr );

// When you are expecting an array..
function ChangeOriginalArray( arr )       // pass as a parameter
{
    var aArr = arr.splice(0);             // make a copy!

    if (aArr["changed"] == false)         // check has same value!
    {
        aArr["newKey"]   = "newVal";      // add a value

        arr["changed"]   = true;          // change original value
    }

    return aArr;
}

oArrFix["newKey"]       == data.arr["newKey"] // false
oArrFix["changed"]      == true               // no, created
data.arr["changed"]     == oArrFix["changed"] // nah, passed by value, not reference

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.