SirDarquan / h5webstorage

Web Storage for Angular 2
http://sirdarquan.github.io/h5webstorage
37 stars 10 forks source link

For @StorageProperty with storageKey, logging it makes its value become "false" #16

Closed ceefour closed 7 years ago

ceefour commented 7 years ago
    @StorageProperty()
    public developerMode?: boolean;// = false;
    @StorageProperty({storageKey: 'b'})
    public _b: boolean;
    @StorageProperty()
    public strProp: boolean;

    constructor(private _logger: Logger, private http: Http, private localStorage: LocalStorage) {
        this._logger.info('Raw: developerMode=', this.developerMode, 'b=', this._b, 'strProp=', this.strProp);
        this._logger.info('Raw: developerMode=', this.developerMode, 'b=', this._b, 'strProp=', this.strProp);
    }

Result:

Raw: developerMode= true b= undefined strProp= undefined
Raw: developerMode= true b= false strProp= undefined

The value of _b becomes false after being logged. This only happens if storageKey is set.

Note: Logger is angular2-logger.

SirDarquan commented 7 years ago

There are some pieces missing that may help me understand what's going on. In your LocalStorage area, am I correct in presuming that the initial state before the constructor is run is {developerMode: true} and that b and strProp are not defined? Given that initial state, the only difference between _b and strProp is the fact that _b uses the alias key b via storageKey which seems to cause the value of b to get set after it is logged. (I wrote this out for future readers because some subtleties don't stick out immediately, plus it helped me actually understand the actual issue).

Thanks, I'll try to understand why this is happening and fix it as soon as I can.

ceefour commented 7 years ago

Yes what you said is entirely correct.

On Dec 6, 2016 10:21, "SirDarquan" notifications@github.com wrote:

There are some pieces missing that may help me understand what's going on. In your LocalStorage area, am I correct in presuming that the initial state before the constructor is run is {developerMode: true} and that b and strProp are not defined? Given that initial state, the only difference between _b and strProp is the fact that _b uses the alias key b via storageKey which seems to cause the value of b to get set after it is logged. (I wrote this out for future readers because some subtleties don't stick out immediately, plus it helped me actually understand the actual issue).

Thanks, I'll try to understand why this is happening and fix it as soon as I can.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SirDarquan/h5webstorage/issues/16#issuecomment-265050099, or mute the thread https://github.com/notifications/unsubscribe-auth/AABeO_1A9o1SQ-wfxHOwia3iLJvv7O71ks5rFNSxgaJpZM4LE9tt .

SirDarquan commented 7 years ago

Ok after some research I now understand why this is happening. A real fix (if it exists) will be a few days from now because I need to test various things but I will tell you how to avoid this and why it's happening, if you're interested.

To avoid this specific situation, simply don't use properties that begin with a single underscore.

TL;DR JavaScript has two features I'm taking advantage of to provide this service: closures and it's dynamic nature. Since each instance of the storage classes are inherited from the BaseStorage class, the the code in BaseStorage can "see" things directly on BaseStorage as well as the inherited class (closure). This is used to store values set by developer code and from storage. As a result, every property created by the StorageProperty decorator has a backing variable with the exact same name, prepended with an underscore (_). But when you set storageKey, I used that value instead. So this leads to the key b having an underscore prepended to it, _b.

During initialization, the code does a check against the normalizedKey (the one with the underscore) to see if it exists already and normally it doesn't. But in this case because the original property name is _b, it mistakes that for it's own property and skips the finalization of the backing variable which set the usable value to what's found in storage (which is undefined in this case since the b key doesn't exist yet). The default value of every property created with StorageProperty is false and since the finalization didn't occur, it surfaced as the usable value. It wasn't logging it that caused this to happen, it was simply using the value that caused it to happen.

Admittedly, prepending an underscore to a key to make it a backing variable was pretty shortsighted. So I'm investigating how to ensure this can't happen again and short of that I'll create a more "complex" prepend string that isn't commonly used and explain it in the documentation.