やりたいこと
localStorage は便利だけど、保存した値が文字列に変換されてしまうので使いにくさを感じるときがある。1
localStorage.setItem('hoge', true);
localStorage.getItem('hoge');
// 'true'
localStorage.setItem('hoge', 123);
localStorage.getItem('hoge');
// '123'
localStorage.setItem('hoge', [1, 2, 3]);
localStorage.getItem('hoge');
// '1,2,3'
localStorage.setItem('hoge', { fuga: 123 });
localStorage.getItem('hoge');
// '[object Object]'
localStorage.clear();
localStorage.getItem('hoge');
// null
Boolean や整数、その他オブジェクトをできるだけそのままの値で保存したい。
方法
- localStorage に setItem() で値を保存する際、JSON 文字列に変換して保存する
- localStorage から getItem() で値を取り出す際、取り出した JSON 文字列をパースする
-
Proxy と Reflect を使って、localStorage の機能を拡張した jsonLocalStorage オブジェクトを作成する2
- そうすることで setItem(), getItem() 以外のインターフェイス (removeItem() や clear() など) をそのまま利用できるようにする
const jsonLocalStorage = new Proxy(localStorage, {
get(target, prop, _receiver) {
if (prop === 'getItem') {
return (keyName) => {
const getItem = Reflect.get(target, prop).bind(target);
const keyValue = getItem(keyName);
return JSON.parse(keyValue);
};
}
if (prop === 'setItem') {
return (keyName, keyValue) => {
const setItem = Reflect.get(target, prop).bind(target);
setItem(keyName, JSON.stringify(keyValue));
};
}
return Reflect.get(target, prop).bind(target);
}
});
jsonLocalStorage.setItem('hoge', true);
jsonLocalStorage.getItem('hoge');
// true
jsonLocalStorage.setItem('hoge', 123);
jsonLocalStorage.getItem('hoge');
// 123
jsonLocalStorage.setItem('hoge', [1, 2, 3]);
jsonLocalStorage.getItem('hoge');
// [1, 2, 3]
jsonLocalStorage.setItem('hoge', { fuga: 123 });
jsonLocalStorage.getItem('hoge');
// {fuga: 123}
jsonLocalStorage.clear();
jsonLocalStorage.getItem('hoge');
// null
参考
-
そのせいで
falseを保存したつもりが'false'になっていてバグったことが 😢 ↩ -
Ruby の SimpleDelegator と同じことがやりたくて ChatGPT に質問したら、Proxy を存在を知りました 🙌 ↩