1

I am working on an app that heavily uses JavaScript. I am attempting to include some object-oriented practices. In this attempt, I have created a basic class like such:

function Item() { this.init(); }
Item.prototype = {
  init: function () {
    this.data = {
      id: 0,
      name: "",
      description: ""     
    }
  },

  save: function() {
    alert("Saving...");
    $.ajax({
      url: getUrl(),
      type: "POST",
      data: JSON.stringify(this.data),
      contentType: "application/json"
    });
  }
}

I am creating Item instances in my app and then saving them to local storage like such:

Item item = new Item();
window.localStorage.setItem("itemKey", JSON.stringify(item));

On another page, or at another time, I am retriving that item from local storage like such:

var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();

Unfortunately, the "save" function does not seem to get reached. In the console window, there is an error that says:

*save_Click (anonymous function) onclick*

I have a hunch that the "(anonymous function)" is the console window's way of saying "calling item.save(), but item is an anonymous type, so I am trying to access an anonymous function". My problem is, I'm not sure how to convert "var item" into an Item class instance again. Can someone please show me?

4
  • Is there any special reason for trying to mimic the classical pattern rather than just using the prototypal pattern? Commented Apr 27, 2012 at 12:45
  • I don't know what the "prototypal" pattern is. Commented Apr 27, 2012 at 14:57
  • Yea, my bad. I actually meant to say prototypal inheritance idiom. Commented Apr 27, 2012 at 19:17
  • What is the "prototypal inheritance idiom"? Do you have a link? I googled it without luck. Commented May 7, 2012 at 12:00

5 Answers 5

3

Short answer:

Functions cannot be serialized into JSON.

Explanation:

JSON is a cross-platform serialization scheme based on a subset of JS literal syntax. This being the case, it can only store certain things. Per http://www.json.org/ :

  • Objects: An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
  • Arrays: An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
  • values: A value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.

Functions cannot be serialized into JSON because another non-JS platform would not be able to unserialize and use it. Consider the example in reverse. Say I had a PHP object at my server which contained properties and methods. If I serialized that object with PHP's json_encode() and methods were included in the output, how would my JavaScript ever be able to parse and understand PHP code in the methods, let alone use those methods?

What you are seeing in your resulting JSON is the toString() value of the function on the platform you're using. The JSON serilizer calls toString() on anything being serialized which isn't proper for JSON.

I believe your solution is to stop storing instances in JSON/local storage. Rather, save pertinent data for an instance which you set back to a new instance when you need.

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

3 Comments

The OP does not [try to] store instances, and no functions at all. He only wants to know how to reinstantiate a Item from his data.
@Bergi Not true at all. She explicitly states that she has an instance of an object with methods, attempted to JSON serialize then unserialize it, and lost the methods on the unserialize side. My proposed solution may not fully address how one would serialize JS objects w/ methods, but I clearly stated what is wrong with her approach and suggested what I consider to be a better way of going about it.
Ah, I see. I had looked on the ajax function.
2

I know this question is answered already, however I stumbled upon this by accident and wanted to share a solution to this problem, if anyone is interested.

instead of doing this:

var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();

do something like this:

// get serialized JSON
var itemData = window.localStorage.getItem("itemKey");
//instantiate new Item object
var item = new Item();
// extend item with data
$.extend(item, JSON.parse(itemData));

// this should now work
item.save();

this will work so long as the function you are wanting to call (ie, save()) is prototypal and not an instance method (often times the case, and is indeed the case in the OP's original question.

the $.extend method is a utility method of jquery, but it is trivial to roll your own.

Comments

0

You cant do that, how can javascript possibly knows that item have a save function ? json doesnt allow functions as datas. just read the json spec , you cant save functions.

what you need to do is to create a serialize and deserialize method in the hash you want to stock. that will specifiy what to export and how you can "wake up" an object after parsing the corresponding json string.

Comments

0

You can only store plain Objects in DOMstorages (cookies, urlparams..., everything that needs [de]serialisation through JSON.stringify/JSON.parse). So what you did when sending the ajax data

ajaxsend(this.data);

also applies to string serialisation. You can only store the data, not the instance attributes (like prototype, constructor etc.). So use

savestring(JSON.stringify(item.data));

which is possible because item.data is such a plain Object. And when restoring it, you will only get that plain data Object back. In your case it's easy to reconstruct a Item instance from plain data, because your Items hold their values (only) in a public available property:

var item = new Item;
item.data = JSON.parse(getjsonstring());

Comments

0

Disclaimer

Not a full time time J.S. Developer, answer may have some minor bugs:

Long Boring Explanation

As mentioned by @JAAulde, your object cannot be serialized into JSON, because has functions, the technique that you are using doesn't allow it.

Many people forget or ignore that the objects that are used in an application, may not be exactly the same as saved / restored from storage.

Short & quick Answer

Since you already encapsulate the data members of your object into a single field, you may want to try something like this:

// create J.S. object from prototype
Item item = new Item();

// assign values as you app. logic requires
item.data.name = "John Doe";
item.data.description = "Cool developer, office ladies, love him";

// encoded item into a JSON style string, not stored yet
var encodedItem = JSON.stringify(item.data)

// store string as a JSON string
window.localStorage.setItem("itemKey", encodedItem);

// do several stuff

// recover item from storage as JSON encoded string
var encodedItem = window.localStorage.getItem("itemKey");

// transform into J.S. object
item.data = JSON.parse(encodedItem);

// do other stuff

Cheers.

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.