Kontynuacja poprzednich lekcji, robimy podobne rzeczy, tym razem z local storage – do dzieła.

Ok, najpierw napiszemy polyfill dla hasItem:

window.localStorage.hasItem = function(key){
    return localStorage.getItem(key !== null);
};

W sumie to nie żaden polyfill, tylko coś, czego nie ma a być powinno. Dobra, teraz funkcja-konstruktor:

function LocalStorageVariable(name, value=null){
    
    this.name = name;
    this.exists = true;

    if(value === null){
        if(localStorage.hasItem(name)){
            this.value = localStorage.getItem(name);
        } else {
            this.value = 0;
            localStorage.setItem(name, 0);
        }
    } else {
        this.value = value;
        localStorage.setItem(name, value);
    }
}

Strasznie trudne to chyba nie jest, parę rzeczy wziąłem pod uwagę, np. że coś już istnieje, albo tworzymy tylko nazwę, bez wartości.

Dobra, drobne funkcje pomocnicze:

LocalStorageVariable.prototype.clearValue = function(){
    localStorage.setItem(this.name, 0);
    this.value = 0;
};

LocalStorageVariable.prototype.remove = function(){
    localStorage.removeItem(this.name);
    this.exists = false;
}

Teraz nasz handler:

const lsvarHandler = {
    set(obj, prop, value){
        if(prop !== 'value') 
            return Reflect.set(...arguments);
        obj.value = value;
        localStorage.setItem(obj.name, value);
        return;
    },

To już powinniśmy znać. Ok, teraz get:

    get(target, prop, receiver){
        if(typeof target[prop] === 'function'){
            return target[prop]();
        }
        if(target.exists === false)
            return;
        localStorage.setItem(target.name, target.value);
        return target.value;

    }
}

Z getem o tyle ciekawa sprawa, że można na nim wołać metody, ale musimy zapomnieć o nawiasach. Niby są inne opcje, choćby apply i call traps, albo zwracanie binda jako funkcji do używania.

Na razie te nasze funkcyjki nie używają żadnych argumentów i można tak się pobawić. Bo idea jest taka, że nie chcemy dawać użytkownikowi lsVar i lsProxy i część zabawy masz z lsVar a część z lsProxy.

Pomyślimy, co tu zrobić, może wrapper jakiś, tym niemniej na razie taki to właśnie śmieszny myk poznaliśmy.

Ok, użycie:

let lsProxy = new Proxy(lsvar, lsvarHandler);
console.log(lsProxy.value);
lsProxy.value = "Jane Doe";
console.log(lsProxy.value);

Możemy też zrobić:

lsVar.clearValue();

Albo:

lsProxy.clearValue;

Generalnie wszystko jest synchronizowane i działa dobrze. Podwaliny pod to, co chcemy napisać…