javascriptarraysfunction-prototypesfunction-constructor

Javascript: Add method to all objects in array


Imagine the following code:

$.get( "ajax/getColorData.php", function( data ) {
  this.colorData = data;
});

now envision that the value of 'data' is:

this.colorData = [
    {
        colorName: 'Red',
        colorIsInRainbow:true
    },
    {
        colorName: 'Orange',
        colorIsInRainbow: true
    },
    {
        colorName: 'Magenta',
        colorIsInRainbow: false
    }
];

Question 1

Now, after I download the data, let's say that I want to add a method, "colorStartsWithR" to every entry in the array. I "think" that rather than define it on every single member of the array, I could somehow define this method on the prototype. But, I'm not sure that I can do that because these objects were not created by me, but were returned by $.get, so it's not clear to me if I'm thinking in the right direction.

Question 2

And to take it a bit further, what if I wanted to add a property to every member of the array, specifically:

    {
        colorName: 'Magenta',
        colorIsInRainbow: false,
        userClickedThisColor:ko.observable()
    }

This way, I can bind (via knockoutjs) the list and include a checkbox. In this case, I question whether or not the prototype would come in handy because each member should get its own ko.observable property. A quick instinct is to do something like:

for (var i=0;i<this.colorData.length;i++)
{
 this.colorData[i].userClickedThisColor=ko.observable()
}

and that works fine, but imagine that there is more than one way to retrieve a list of colors, or that a user can create new color instances, and that the customization I did above is more complicated. I would now need to duplicate the above "add-on" logic. Is there a smarter way?

Having spent most of my time in strongly-typed languages, sometimes these things aren't as obvious to me. Thanks for any suggestions...

-Ben


Solution

  • Well, those objects don't have a special prototype, so you can't add members to it. I think these are the alternatives:

    1) Add the members to each instance (I know you don't like it, but it's an option). I'd go for this option

    2) Just create a method, and pass each object as a parameter or as this with fn.call()

    3) Create a "class" with the added members, then create instances of it passing the original object in the constructor. Not ideal, but maybe you have to do it.

    function Color(plainObj){
       this.colorName: plainObj.colorName;
       this.colorIsInRainbow: plainObj.colorIsInRainbow;
    
       //if you want all properties to be copied dynamically, uncomment the following:
       //for(var key in plainObj) this[key] = plainObj[key];                 
    
       this.userClickedThisColor = ko.observable()
       ...
    }
    Color.prototype.colorStartsWithR = function() {
        return this.colorName.charAt(0) == "R";
    };
    
    //etc
    

    Then, to apply it

    for(var i=0; i<colorData.length; i++){
       colorData[i] = new Color(colorData[i]); //Overwrites original colorData array
    }
    

    Hope this helps. Cheers