localStorage

zzwwoonn·2022년 4월 16일
0

Java Script

목록 보기
15/29

window.localStorage
이전에 배웠듯 전역 객체인 window는 생략 가능하다. localStorage 읽기 전용 속성을 사용하면 Document 출처의 Storage 객체에 접근할 수 있다. 저장한 데이터는 브라우저 세션 간에 공유된다. localStorage는 sessionStorage와 비슷하지만, localStorage의 데이터는 만료되지 않고 sessionStorage의 데이터는 페이지 세션이 끝날 때, 즉 페이지를 닫을 때 사라지는 점이 다르다.

myStorage = window.localStorage;
// 현재 출처의 로컬 저장 공간에 접근할 수 있는 Storage 객체.

CRUD 메소드

현재 도메인의 로컬 Storage 객체에 접근한 후,

Create

localStorage 항목 하나 추가
(로컬 스토리지에서 바라봤을 때 항목 추가를 create라고 바라봤다)

localStorage.setItem('myCat', 'Tom');

Read

위에서 추가한 localStorage 항목 접근(읽기)

const cat = localStorage.getItem('myCat');

Delete

localStorage 항목 제거

localStorage.removeItem('myCat');

Delete All

localStorage 항목의 전체 제거

localStorage.clear();

주의할 점

일반 객체처럼 사용하기

localStorage의 키를 얻거나 설정할 때, 아래처럼 일반 객체와 유사한 방법을 사용할 수 있다.

// 키 설정하기
localStorage.test = 2;

// 키 얻기
alert( localStorage.test ); // 2

// 키 삭제하기
delete localStorage.test;

하위 호환성 때문에 아직 이런 방법이 지원되기는 하지만, 다음과 같은 이유로 추천하지 않는다.

  • 사용자는 length나 toString, localStorage의 내장 메서드를 키로 설정할 수 있습니다. 이렇게 되면 getItem, setItem은 정상적으로 작동해도, 일반 객체처럼 다룰 때 에러가 발생할 수 있다.
let key = 'length';
localStorage[key] = 5; // TypeError: Cannot assign to read only property 'length'...
  • 데이터를 수정하면 storage 이벤트가 발생하는데, 이 이벤트는 localStorage를 객체처럼 접근할 땐 일어나지 않는다.

키 순회하기

localStorage는 '키(Key)’를 사용해 값(Value)을 얻고(get), 설정(set)하고, 삭제(delete)할 수 있게 해준다. 그렇다면 키나 값 전체는 어떻게 얻을 수 있을까?

아쉽게도 로컬스토리지 객체는 iterable 객체가 아니다.

iterable object
반복 가능한(iterable, 이터러블) 객체는 배열을 일반화한 객체이다. 이터러블 이라는 개념을 사용하면 어떤 객체에든 for..of 반복문을 적용할 수 있다. 배열은 대표적인 이터러블이다. 배열 외에도 다수의 내장 객체가 반복 가능하다. 문자열 역시 이터러블의 예이다.

하지만 배열처럼 다루면 전체 키-값을 얻을 수 있다.

for (let i=0; i<localStorage.length; i++) {
  let key = localStorage.key(i);
  alert(`${key}: ${localStorage.getItem(key)}`);
}

일반 객체를 다룰 때처럼 for key in localStorage 반복문을 사용해도 전체 키-값을 얻을 수 있다. 하지만 이 방법을 사용하면 필요하지 않은 내장 필드까지 출력된다.

// 좋지 않은 방법
for(let key in localStorage) {
  alert(key); 
  // getItem, setItem 같은 내장 필드까지 출력됩니다.
  
  // proxyConsoleLog.js:12 _ym32184394_lsid, 
  // _ym_uid, length, clear, 
  // getItem, key, removeItem, setItem ~~~ 
}

for key in localStorage 반복문을 사용하려면 hasOwnProperty를 이용해 프로토타입에서 상속받은 필드를 골라내야 한다.

for(let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue; // setItem, getItem 등의 키를 건너뜁니다.
  }
  alert(`${key}: ${localStorage.getItem(key)}`);
}

아니면 아래처럼 Object.keys로 '자기 자신’의 키를 받아온 다음 순회하는 방법을 사용할 수도 있다.

let keys = Object.keys(localStorage);
for(let key of keys) {
  alert(`${key}: ${localStorage.getItem(key)}`);
}

Object.keys는 해당 객체에서 정의한 키만 반환하고 프로토타입에서 상속받은 키는 무시하기 때문이다.

문자열만 사용

localStorage의 키와 값은 반드시 문자열이어야 한다. 숫자나 객체 등 다른 자료형을 사용하게 되면 문자열로 자동 변환된다.

sessionStorage.user = {name: "John"};
alert(sessionStorage.user); // [object Object]

JSON을 사용하면 객체를 쓸 수 있긴 합니다.

sessionStorage.user = JSON.stringify({name: "John"});

let user = JSON.parse( sessionStorage.user );
alert( user.name ); // John

디버깅 등의 목적으로 스토리지 객체 전체를 문자열로 변환하는 것도 가능하다.

실습

<!-- HTML code -->

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width-device-width", initial-scale="1.0">
        <link rel="stylesheet" href="style.css">
        <title>#4</title>
    </head>
</html>

<body>
    <form class="hidden" id="login-form">
        <input 
            required 
            maxlength = "15"   
            type="text" 
            placeholder="what is your name?"
        />
        <button>Log in</button>
    </form>
    <h1 class="hidden" id="greeting"></h1>
    <script src="app.js"></script>
</body>
// JS code

const loginForm = document.querySelector("#login-form");
const loginInput = document.querySelector("#login-form input");
const greeting = document.querySelector("#greeting");

const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KEY = "username";


function onLoginSubmit(event) {
    event.preventDefault();
    // 브라우저의 기본 동작을 막아준다. => 페이지 새로고침을 막아준다.

    const username = loginInput.value;

    localStorage.setItem(USERNAME_KEY, username);
    paintGreetings(username);
}

function paintGreetings(username) {
    loginForm.classList.add(HIDDEN_CLASSNAME);
    greeting.innerText = `Hello ${username}`;
    greeting.classList.remove(HIDDEN_CLASSNAME);
}

const saveUsername = localStorage.getItem(USERNAME_KEY);

if (saveUsername === null){
    loginForm.classList.remove(HIDDEN_CLASSNAME);
    loginForm.addEventListener("submit", onLoginSubmit);
} else {
    paintGreetings(saveUsername);    
    // 사실 saveUsername은 로컬 스토리지에 저장되어 있으니 
    // 굳이 인자로 전해줄 필요가 없음
    // 근데 그러면 로컬 스토리지를 두 번 열어봐야겠지
}

0개의 댓글