0

I am a beginner to Javascript. I am trying to print an array of objects from LocalStorage. I stringified the array before putting it in, then parsed it when retrieving it. In addition, I added a 'toString()' method to my object's class.

class Book {
    constructor(title, commentary) {
        this.title = title;
        this.commentary = commentary == undefined ? "" : commentary;
        this.date = new Date();
    }
    toString() {
        return `"${this.title}"`;
  }
}

var mybooks = [];
mybooks.push(new Book("The Hobbit"));
mybooks.push(new Book("Pride and Prejudice"));
console.log("books: " + mybooks.toString());

localStorage.setItem("mybooks", JSON.stringify(mybooks));
var books = JSON.parse(localStorage.getItem("mybooks")); 

console.log("books: " + books.toString());

However, here is the output:

books: "The Hobbit","Pride and Prejudice"
books: [object Object],[object Object]

Ideally, the second line should be like the first line. Any help would be appreciated! Thank you.

I've looked online and have seen several similar threads, but most of them store arrays of primitives, or didn't convert the array to a string before storing it, or were the result of typos.

4
  • Avoid using javascript method as function name like here toString() is already a javascript method Commented Aug 13, 2024 at 21:10
  • 1
    @Mehdi There is nothing wrong with overriding the default toString method from Object.prototype. On the contrary, it's rather recommended! Commented Aug 13, 2024 at 21:12
  • Your problem is that JSON.parse does create plain objects instead of constructing Book instances. You'll need to use a reviver callback, or use books.map(object => new Book(…)). Preferably, create a static Book.fromJSON to help you with that - in particular, if you want to restore the .date (as you currently can't pass that to your constructor). Commented Aug 13, 2024 at 21:14
  • @Bergi you are absolutely right actually it is also done in the MDN link :-) Commented Aug 13, 2024 at 21:16

1 Answer 1

0

Your call to JSON.parse, will give you an array of plain objects, not of Book objects.

Another issue is the date: JSON.stringify will turn this into a string, but JSON.parse will not turn it back into a Date instance.

To solve both issues, it would be handy to modify your constructor so it can take an optional date argument. That way the constructor can be used to create a Book instance for data you get from JSON.parse.

Also, you would need some logic to recognise that some object parsed from JSON was intended to be a Book instance. Maybe it would be nice to add another property in the JSON representation, which indicates that the object really is the JSON representation of a Book instance, like "_class": "Book".

One way to get an array of Book instances from the JSON string, is to use the reviver optional argument when calling JSON.parse. That reviver could check for the extra "_class" property to decide when to call the Book constructor.

Below is one of the ways to make it work. Note that for this question it is not relevant to use local storage. It is enough to create the JSON and then parse it again:

class Book {
    constructor(title, commentary, date=new Date()) { // Allow for optional date argument
        this.title = title;
        this.commentary = commentary ?? "";
        // Allow date argument to be a parseble string (ISO); default to current date
        this.date = date ? new Date(date) : new Date();
    }
    toJSON() {  // This gets called when calling JSON.stringify
        return {...this, _class: this.constructor.name } // Add special key
    }
    toString() {
        return `"${this.title}", ${this.date.getFullYear()}`;
    }
}

function reviver(key, value) {
    if (Object(value)._class === "Book") { // Read special property
        return new Book(value.title, value.commentary, value.date);
    }
    return value;
}

const mybooks = [
    new Book("The Hobbit"),
    new Book("Pride and Prejudice")
];
console.log("books: " + mybooks.join("; "));

const json = JSON.stringify(mybooks);
const books = JSON.parse(json, reviver);
console.log("books: " + books.join("; "));

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.