Zachary Scott
Zachary Scott

Reputation: 21172

Javascript: How to turn a JSON array of object back in to the Object type sharing prototypes?

If you have an array of product objects created from JSON, how would you add a prototype method to the product objects so that they all point to the same method? How would you train JavaScript to recognize all product objects in an array are instances of the same class without recreating them?

If I pull down a JSON array of Products for example, and want each product in the array to have a prototype method, how would I add the single prototype method to each copy of Product?

I first thought to have a Product constructor that takes product JSON data as a parameter and returns a new Product with prototypes, etc. which would replace the data send from the server. I would think this would be impractical because you are recreating the objects. We just want to add functions common to all objects.

Is it possible to $.extend an object's prototype properties to the JSON object so that each JSON object would refer to exactly the same functions (not a copy of)?

For example:

var Products = [];
Products[0] = {};
Products[0].ID = 7;
Products[0].prototype.GetID = function() { return this.ID; };
Products[1].ID = 8;
Products[1].prototype = Products[0].prototype;  // ??

I know that looks bad, but what if you JQuery $.extend the methods to each Product object prototype: create an object loaded with prototypes then $.extend that object over the existing Product objects? How would you code that? What are the better possibilities?

Upvotes: 6

Views: 1914

Answers (6)

BCDeWitt
BCDeWitt

Reputation: 4773

IMO I found a pretty good answer right here:

Return String from Cross-domain AJAX Request

...I could serialize my data in the service as a JSON string and then further wrap that in JSONP format? I guess when it comes over to the client it would give the JSON string to the callback function. That's not a bad idea. I guess I would also have the option of sending a non-JSON string which might allow me to just use eval in the callback function to create new Person objects. I'm thinking this would be a more efficient solution in both speed and memory usage client-side.

Upvotes: 1

BCDeWitt
BCDeWitt

Reputation: 4773

So, if I'm getting this all correctly, this is a more complete example of KOGI's idea:

// Create a person class
function Person( firstName, lastName ) {
    var aPerson = {
        firstName:  firstName,
        lastName:   lastName
    }

    // Adds methods to an object to make it of type "person"
    aPerson = addPersonMethods( aPerson );
    return aPerson;
}
function addPersonMethods( obj ) {
    obj.nameFirstLast = personNameFirstLast;
    obj.nameLastFirst = personNameLastFirst;
    return obj;
}
function personNameFirstLast() {
    return this.firstName + ' ' + this.lastName;
}
function personNameLastFirst() {
    return this.lastName + ', ' + this.firstName;
}

So, with this structure, you are defining the methods to be added in the addPersonMethods function. This way, the methods of an object are defined in a single place and you can then do something like this:

// Given a variable "json" with the person json data
var personWithNoMethods = JSON.parse( json );    // Use whatever parser you want
var person = addPersonMethods( personWithNoMethods );

Upvotes: 1

Casey Chu
Casey Chu

Reputation: 25463

First, one problem is that prototype methods are associated when the object is created, so assigning to an object's prototype will not work:

var Products = [];
Products[0] = {};
Products[0].prototype.foo = function () { return 'hello' } // ***

Products[0].foo(); // call to undefined function

(*** Actually, the code fails here, because prototype is undefined.)

So in order to attach objects, you'll need to assign actual functions to the object:

Products[0].foo = function () { return 'hello'; };

You can create a helper function to do so:

var attachFoo = (function () { // Create a new variable scope, so foo and
                               // bar is not part of the global namespace

    function foo() { return this.name; }
    function bar() { return 'hello'; }

    return function (obj) {
        obj.foo = foo;
        obj.bar = bar;
        return obj; // This line is actually optional,
                    // as the function /modifies/ the current
                    // object rather than creating a new one
    };

}());

attachFoo(Products[0]);
attachFoo(Products[1]);

// - OR -
Products.forEach(attachFoo);

By doing it this way, your obj.foos and obj.bars will all be referencing the same foo() and bar().

Upvotes: 2

Robert
Robert

Reputation: 21388

For one, you're not modifying the Products[0].prototype, you're modifying Object.prototype, which will put that function on the prototype of all objects, as well as making it enumerable in every for loop that touches an Object.

Also, that isn't the proper way to modify a prototype, and ({}).prototype.something will throw a TypeError as .prototype isn't defined. You want to set it with ({}).__proto__.something.

If you want it to be a certain instance you need to create that instance, otherwise it will be an instance of Object.

You probably want something like:

var Product = function(ID) {
    if (!this instanceof Product)
        return new Product(ID);

    this.ID = ID;

    return this;
};

Product.prototype.GetID = function() { 
    return this.ID;
};

Then, fill the array by calling new Product(7) or whatever the ID is.

Upvotes: 2

joekarl
joekarl

Reputation: 2118

Could try doing something like this (without jquery) Basic prototypal object:

function Product(id){
    this.id = id;
}
Product.prototype.getId() = function(){return this.id;};

var Products = [];
Products[0] = new Product(7);
Products[1] = new Product(8);
Products[2] = new Product(9);

alert(Products[2].getId());

Upvotes: 1

KOGI
KOGI

Reputation: 3989

You could do this...

function product( )
{
   this.getId = product_getId;

    // -- create a new product object
}

function product_getId( )
{
   return this.id;
}

This way, although you will have several instances of the product class, they all point to the instance of the function.

Upvotes: 1

Related Questions