1

This question is a follow-up to my last question: JavaScript Serialization and Methods. While related, I believe this is different which is why I started this thread. Regardless...

I have a complex tree of objects that I need to pass around between pages. Because of this, I'm attempting to serialize and deserialize my objects. One of my objects in particular has several collections of child objects. Each of those child object types has a function on it, that I'm trying to call. Unfortunately, I am not having any luck. I setup a test project in an attempt to isolate the problem and get to the bottom of it. Currently, I have my JavaScript Objects defined in a seperate file called objects.js. That file looks like this:

objects.js

function MyChild() { this.init(); }
MyChild.prototype = {
    data: {
        id: 0,
        fullName: "",
    },

    init: function () {

    },

    save: function (key) {

    },

    load: function (key) {

    },

    test: function () {
        alert("Testing Child functions");
    }
}

function MyParent() { this.init(); }
MyParent.prototype = {
    data: {
        id: "",
        children: null
    },

    init: function () {
        this.data.children = [];
    },

    save: function (key) {
        window.localStorage.setItem(key, JSON.stringify(this.data));
    },

    load: function (key) {
        var temp = window.localStorage.getItem(key);
        if (temp != null) {
            this.data = JSON.parse(temp);
            $.each(this.data.children, function (i, r) {
            });
        }
    },

    test: function () {
        alert("Testing Parent functions");
    }
}

I am creating, serializing, deserializing, and attempting to interact with these objects in an .html file. That .html file is shown here:

test.html

<div>
    <input id="button1" type="button" value="Create Object Tree" onclick="button1Click();" /><br />
    <input id="button2" type="button" value="Retrieve and Execute" onclick="button2Click();" /><br />
</div>

<script type="text/javascript">
    function button1Click() {
        var child = new MyChild();
        child.data.id = 1;

        var p = new MyParent();
        p.data.id = "A";
        p.data.children.push(child);
        p.save("A");
    }

    function button2Click() {
        var storedParent = new MyParent();
        storedParent.load("A");

        storedParent.test();                          // This works
        alert(storedParent.data.children.length);     // This displays "1" like I would expect
        alert(storedParent.data.children[0].data.id); // This does NOT work. 
        storedParent.data.children[0].test();         // This does NOT work.   
    }
</script>

I'm not sure what I'm doing wrong. Can someone please help me understand this? Can somone please help me fix my example. I have a hunch that I'm not serializing MyChild objects properly. But I don't understand how I should be serializing / deserializing them in relation to MyParent.

Thank you!

3
  • did you really mean to put data in the prototype chain? That would make the data shared by every instance. Commented Mar 12, 2012 at 16:09
  • no. I'm don't fully know what I'm doing. I'm trying to understand this object-oriented JavaScript thing. I come from a C# background. I assumed this approach created instance-level variables. Am I wrong? How do I fix it? Commented Mar 12, 2012 at 16:20
  • @user208662 what Alnitak mentions above is what was wrong with the accepted answer on your other post ;) Commented Mar 12, 2012 at 17:59

1 Answer 1

2

You need to store your data within each object, not within its prototype.

Data stored in in the prototype of an object is shared between all instances and won't be serialised by JSON.stringify, so your object data never ends up in the local storage.

To fix, add data to this within the this.init() function:

MyChild.prototype = {
    init: function() {
        this.data = {
            id: 0,
            fullName: ""
        };
    },
    ...
}

MyParent.prototype = {
    init: function() {
        this.data = {
            id: "",
            children: []
        }
    },
    ...
}

Working sample at http://jsfiddle.net/alnitak/fdwVB/

Note that attaching the functions in MyChild to the retrieved data is tricky. The code below appears to work:

load: function(key) {
    var temp = window.localStorage.getItem(key);
    if (temp != null) {
        this.data = JSON.parse(temp);
        var children = this.data.children;
        for (var i = 0; i < children.length; ++i) {
            children[i] = $.extend(new MyChild(), children[i]);
        }
    }
},

But note that it works by constructing a new "default" child for each retrieved entry, and then overwriting that child's data with the serialised values.

This could be problematic if the constructor has "side effects".

A better approach might be to allow the MyChild() constructor to take an optional complete object of initial values to use instead of the default values.

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

4 Comments

Thank you for your response. However, this still won't let me call the "test" function on "MyChild. For instance, if I do "storedParent.data.children[0].test()" I get a TypeError.
ah, yes, didn't notice that part. The issue you have there is that deserialising the data recreates the data, but doesn't attach the object to its prototype. I'll see if I can fix the fiddle to achieve that.
thank you for your persistence. for the life of me, I can't figure it out.
I just noticed you solved it. Seriously, I cannot say thank you enough.

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.