3

The following code from Mr. Guria's answer.

Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
}

Storage.prototype.getObject = function(key) {
    var value = this.getItem(key);
    return value && JSON.parse(value);
}

This is a cleverly solution. How to improve this solution to the 'dot notation'?

For instance

My stored object

var user = { "name":"testName", "surname":"testSurname" };
localStorage.setObject("user", user);

My purpose is to get name content by this way

   var name = localStorage.user.name;

I don't know how it is developed javascript prototype.

Community
  • 1
  • 1
efkan
  • 12,991
  • 6
  • 73
  • 106

2 Answers2

2

Since you have a setter, that gives you enough control over the stores to create your behavior. Since key/values are stored, we can look for last time's values on boot, and upgrade them transparently (if needed). One nice thing about using setObject() and setItem() is that our re-defined properties don't get in the way of re-setting new values. v

I still think this could cause conflicts with other apps that use localStorage, and it reserves the "ƒ" char as special, but if you use your setObject() method each time to save objects, the following works well:

(function() {

    function makeDot(key, value){            
        Object.defineProperty(localStorage, key, {
            configurable: true,
            enumerable: true,
              get: function() {
                  return typeof value==="string" && value.slice(0,1)==="ƒ" ? 
                       JSON.parse(value.slice(1)) : 
                       value;
             }
        });
    }

    Storage.prototype.setObject = function(key, value) {
        this.setItem(key,  "ƒ"+JSON.stringify(value));
        makeDot(key, value);
    }
     // upgrade existing object stores:   
    Object.keys(localStorage).forEach(function(a){
        var v=localStorage[a];
        if(typeof v==="string" && v.slice(0,1)==="ƒ"){
               makeDot(a, v);    
        }
    });


}());


var user = {
    "name": "testName",
    "surname": "testSurname"
};

localStorage.setObject("user", user); //save object

alert( localStorage.user.surname ); // shows: "testSurname"

see http://jsfiddle.net/hrepekbb/ to kick the tires

if you want to set objects with the dot notation, well then then you need to use an observer or maybe proxy reflecting localStorage, but neither of those options are quite ready for prime-time yet.

dandavis
  • 16,370
  • 5
  • 40
  • 36
  • Today I tried to set value with the same way. I took your advice unfortunately I wasn't able to manage with observer. Do you know any way to overcome this? Thank you. – efkan Sep 24 '14 at 14:15
  • with an observer, the set value would not be available right away. a setTimeout to read after writing might be enough, but it's simply not going to work as well because localStorage is sync. which means it waits for us, with observers, we need to wait on it. If you are not setting new localStorage values, you can use the slightly more supported (polyfill-able) Object.watch(), but i don't think it's "thread-safe" like the above code, so you still need a small pause between setting and fetching. that's why i didn't get into setting objects directly: it doesn't work well, as apsillers alluded to. – dandavis Sep 24 '14 at 17:13
0

You can't. Stored values from localStorage are always JSON strings. localStorage.getObject("user").name is the best you can do.

You could set up a property with an access descriptor to act a a "proxy" property. Such a proxy property map onto a stored value, but you would need to do that for every value you wanted to access.

Object.defineProperty(localStorage, "user", {
    get: function() { return localStorage.getObject("realUserKey"); },
    set: function(v) { localStorage.setObject("realUserKey", v); }
});

Here, the realUserKey value of localStorage is being set and persisted, but the value is transparently accessible from the user property. Note that this setup does not persist and needs to be re-declared each page load, just like the getObject and setObject functions are.

To reiterate: there is no way to generalize this strategy to arbitrary key values (not until the ES6 standard comes out of development and sees deployment in browsers). You must declare each "proxy" property explicitly.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • before today, i thought you were right. i'd tried hacking together stuff like this before and always failed. But the reason i failed was that i wanted to _set_ with a assignment to a path; using a setter method changes all that and allows re-defining every output that needs it, either just in time or ahead of time in load... – dandavis Sep 19 '14 at 20:49
  • Than you for your answer Apsillers. Already I used "localStorage.getObject("user").name". Thanks anyway. Have a nice day.. – efkan Sep 20 '14 at 11:44