1
\$\begingroup\$

As I am a new programmer, it is very often that I find features of JavaScript that aren't any good, or I am not using them well.

I recently discovered a module for storing data called localStorage and I thought of many ways to use it. One is to implement it into a code I have already created to make things easier for the user to use.

I thought of saving all of the data kinda like this.

const save = () => {
    let saveInfo = [
        els.scoreInEl.value, //input 
        els.maxInEl.value, //input
        els.percentInEl.value, //input
        els.percentInEl.textContent, //output
        els.gradeEl.textContent, //output
        els.scoreUp.textContent, //output
        els.scoreDown.textContent, //output
        els.percentOut.textContent //output
    ];
    localStorage.setItem('savedInfo',saveInfo);
}
    const removeSave = () => {localStorage.removeItem('savedInfo');};
    window.onload = () => {
        let savedInfo = localStorage.getItem('savedInfo')
        if(savedInfo == null) {return} else {
            savedInfo.split(',').forEach((x,i) => {
                let currObject = Object.keys(els)[i];//els basically has all of the names in savedInfo this is just more for implementation
                els[currObject].value = x'
            }
        }
    }

But I ended up doing what is below, the difference is that in saveInfo I don't have all of the outputs, instead, later I plug those inputs into the same equation that calculated the outputs.

I thought this would be less intensive on the computer as you are saving 1/3 of the information that is being stored. and although it probably doesn't matter on this level.

The reason why save () doesn't have any parameters is because I have all the information needed, and it is only needed when you click the save button.

This is the new code:

const save = () => {
    let saveInfo = [
        els.scoreInEl.value, //input 
        els.maxInEl.value, //input
        els.percentInEl.value, //input
    ];
    localStorage.setItem('savedInfo',saveInfo);
}
    const removeSave = () => {localStorage.removeItem('savedInfo');};
    window.onload = () => {
        let savedInfo = localStorage.getItem('savedInfo')
        if(savedInfo == null) {return} else {
            savedInfo.split(',').forEach((x,i) => {
                let currObject = Object.keys(els)[i];//basically has all of the names in savedInfo
                els[currObject].value = x;
            }
            calc();//function I use to make those values, to begin with
        }
    }

I am wondering if this was a good way to handle the localStorage along with any ways I can improve the way I am handling the storing and removing data, along with anything else that may be good to know.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

localStorage

localStorage can be used as an object. This eliminates the need to use the verbose storage.setItem, storage.getItem, and storage.removeItem calls. The standard getters and setters will be invoked on all modern broswers.

Examples

  • Set item localStorage.test = "A";
  • Get item const test = localStorage.test;
  • Remve item delete localStorage.test;

Never trust local storage

localStorage should never be trusted as it can be blocked, modified (even during a write), and deleted without notice or warning.

Local storage has limited memory which can change from browser to browser and even from client to client depending on the browsers setup. This is approx 5Mb. (Note JS strings are Unicode thus 5Mb will let you store 2.5million characters)

JSON

localStorage values are always stored as strings. To store objects you can use the JSON API.

Using the JSON api store data using an object as the root, avoid storing arrays as the root object.

When using JSON.stringify and JSON.parse on untrusted data wrap the calls in a try catch.

Code

  • You define a function that can never be used ? const removeSave = () => {localStorage.removeItem('savedInfo');};

  • There is no need to use the globalThis reference window as it is the default object.

  • Never set listeners directly eg window.onload as they can not be trusted. Use addEventListener to add listeners.

  • Use constants for values that do not change. Eg let saveInfo = [ should be const saveInfo = [

  • JavaScript uses undefined to mean "undefined". null is an object used as a place holder to mean "declared but not assigned".

    Note that JSON stringify does the same. null as a placeholder adding the key with a value of null while undefined will not add the key value pair.

Rewrite

Error handling as stubs as I am unsure as to your intentions.

// Assumes els as object and calc as function are defined correctly.
addEventListener("load", onLoadListener);
function saveLocal() {
    try {
        localStorage.savedInfo = JSON.stringify({
            scoreInEl: els.scoreInEl.value, 
            maxInEl: els.maxInEl.value,
            percentInEl: els.percentInEl.value, 
        });
    } catch(e) { 
        // In this case the values if proprieties of elements this will never 
        // cause stringify to throw However use try catch for anything not a basic type 
    }       
}
function deleteLocal() { delete localStorage.savedInfo }
function onLoadListener() {
    if (localStorage.savedInfo) {
        try {
            for (const [key, value] of JSON.parse(localStorage.savedInfo)) {
                els[key] && (els[key].value = value);
            }
        } catch(e) { /* handle JSON parse error */ }
    }
    calc();            
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.