views:

746

answers:

5

Writing a ton of web applications leveraging JSON/AJAX, I find myself returning tons literal javascript objects (JSON). For example, I may be request all the Cats from GetCats.asp. It would return:

[
  { 'id': 0, 'name': 'Persian' },
  { 'id': 1, 'name': 'Calico' },
  { 'id': 2, 'name': 'Tabby' }
]

Now, these are all Cat objects with behaviors. However, if I define a Cat object, function Cat() { }, I know of no EFFICIENT way to coax these literal objects into the behaviors of a user defined object.

I can do this by brute force of iterating through them and assigning functions, but it's not going to be pretty. Is there a nice, one line(or few), way of somehow "casting" this behavior onto these literal objects?

+2  A: 

There's no getting around the fact that you will have to iterate through all of your simple objects and change them to a different kind of object. You cannot avoid the loop. That being said you could create a constructor that takes a simple object like this and copies those values into the new instance.

Like this:

function Cat(c) {
  this.id = c.id;
  this.name = c.name;
}
Cat.prototype.meow = function() {alert('meow');}
Cat.prototype.displayName= function() {alert(this.name);}

var cats = [
  { 'id': 0, 'name': 'Persian' },
  { 'id': 1, 'name': 'Calico' },
  { 'id': 2, 'name': 'Tabby' }
];

for (i=0,len=cats.length; i<len; i++) {
  cats[i] = new Cat(cats[i]);
}

cats[0].meow();  // displays "meow"
cats[0].displayName();  // display "Persian"
Benry
A: 

Assign each object an appropriate prototype:

var list = [
  { 'id': 0, 'name': 'Persian' },
  { 'id': 1, 'name': 'Calico' },
  { 'id': 2, 'name': 'Tabby' }
];


for (obj in list)
{
  obj.prototype = new Cat();
}
JSBangs
This won't work because their objects, not classes.
Benry
Javascript doesn't have classes, it uses prototype based inheritance. This won't work for a different reason - those objects are notational objects, not first class objects that can be instanced - which are actually functions in javascript.
Eran Galperin
Well, that hack David Flanagan calls them classes. I'll stick with him. But if we're really going pick nits, let's call them constructor functions.
Benry
To my knowledge, this works for obj.__proto__, and only in Javascript (not Jscript/IE).
Borgar
A: 

If you're using the json2 parser (or another one with a compatible interface), you can simply provide a callback to replace the raw objects with custom objects:

var catSource = '[ { "id": 0, "name": "Persian" }, { "id": 1, "name": "Calico" }, { "id": 2, "name": "Tabby" } ]';

function Cat(id, name)
{
   this.id = id;
   this.name = name;
}
Cat.prototype = 
{
   toString: function()
   {
      return this.name;
   }
};

function doStuff()
{
   var cats = JSON.parse(catSource, function(key, val)
   {
      // some expression to detect the type of val 
      if ( val.id !== undefined && val.name !== undefined )
         return new Cat(val.id, val.name);
      return val;
   });
   alert(cats);
}
Shog9
A: 

do you use prototype framework? if yes - here is an example


var cats = [
    {id: 15, name: 'Tables', count:45 },
    {id: 23, name: 'Chairs', count:34 }
];
var catsObjects = [];
cats.each(function(item){
    var newObject = new Cat();
    Object.extend(newObject, item);
    catsObjects.push(newObject);
});

basically Array.each function is the same as "for i < Array.length"
and Object.extend is the same as property-by-property adding properties to newObject

small_jam
A: 

Extending @Benry's answer.

I find that having an extend function to copy properties of one object onto another is essential. There is a semi-tradition for putting it onto Object; Object.extend() exists in many smaller libraries (NB: this is not the same as Object.prototype).

Object.extend = function ( take, give ) {
  for (var k in give) {
    if (give.hasOwnProperty(k)) {
      take[k] = give[k];
    }
  }
  return take;
}

This has the plus that you can use nice readable literal notation when writing your code:

function Cat (c) {
  Object.extend( this, ( c || this.defaults )  );
}

Object.extend(Cat.prototype, {

  meow : function() {
    alert( 'Meow, my name is ' + this.name );
  },

  defaults : {
    name : 'I have no name', 
    id   : null
  }

});

You can then create your army of cats quite simply:

var cats = [
  { 'id': 0, 'name': 'Persian' },
  { 'id': 1, 'name': 'Calico' },
  { 'id': 2, 'name': 'Tabby' }
];

for (i=0,len=cats.length; i<len; i++) {
  cats[i] = new Cat( cats[i] );
}

cats[0].meow();  // displays "meow, my name is Persian"
Borgar