クッキーより便利になったブラウザ標準ストレージ - Web Storage

2012年10月18日(木)
山田 祥寛(YAMADA, Yoshihiro)

Web Storage(以降、ストレージ)とは、ブラウザ標準で用意されたデータストアの一種です。データを特定するための名前(キー)と値との組み合わせでデータを管理することから、Key-Value型データストアと呼ばれることもあります。あまりに複雑なデータ管理には不向きですが、ちょっとしたデータを管理するのに有効です(*)

*)例えばAmazonでは「この商品を買った人はこんな商品も買っています」という表示項目のページ番号管理に、ストレージを利用しています。

このようなデータストアとしては、従来、クッキー(Cookie)がありましたが、表1のような違いがあります。環境が許すのであれば、今後はストレージを優先して利用することをお勧めします。

表1:ストレージとクッキーの違い

項目 ストレージ クッキー
データサイズ 大(5MB) 小(4KB)
有効期限 なし あり
通信 発生しない リクエスト都度、サーバにも送信
[第5回目次]
  • TIPS 034:ストレージにデータを保存する
  • TIPS 035:ストレージのデータを取得する
  • TIPS 036:ストレージのデータをツールから確認する
  • TIPS 037:ストレージからすべてのデータを取り出す
  • TIPS 038:ストレージ上のデータを削除する
  • TIPS 039:ストレージにオブジェクトを出し入れする
  • TIPS 040:ストレージの登録/更新/削除を監視する

サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。

ストレージは、大きくセッションストレージとローカルストレージに分類できます。両者の違いは有効範囲です。

セッションストレージ(Session Storage)は、ブラウザが起動している間だけ有効です。ブラウザを閉じたタイミングでデータは破棄されますし、異なるウィンドウ/タブ同士でもデータを共有することはできません。

一方、ローカルストレージ(Local Storage)は、オリジン単位でデータを管理します。ブラウザを閉じてもデータが消えることはありませんし、異なるウィンドウ/タブからも同じデータを共有することが可能です。

オリジンとは「http://www.wings.msn.to:8080/」のように、「プロトコル://ホスト:ポート番号」の組み合わせのことです。ストレージはオリジンの単位で独立していますので、現在のホストで保存したデータを異なるホストで読み込むということはできません。

アプリを利用している間だけ維持しておきたい情報はセッションストレージを、閉じたあとも維持したい情報はローカルストレージという使い分けになるでしょう。先ほどのAmazonの例であれば、その場限りの情報なのでセッションストレージを利用しています。

表2:WebStorageの対応バージョン

ブラウザ 対応バージョン
Internet Explorer 8以降
Firefox 3.6以降
Google Chrome 8以降
Safari 5以降
Opera 11以降

TIPS 034:ストレージにデータを保存する

さまざまな記法で、ストレージにデータを保存してみましょう。例えば以下は、現在時刻をローカルストレージに保存する例です。

[リスト01]ストレージに現在時刻を保存するコード(set.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    // ストレージが利用できるかをチェック(1)
04    if (localStorage) {
05      // ローカルストレージを呼び出し(2)
06      var storage = localStorage;
07      var current = (new Date()).toLocaleString();
08      // ストレージに現在時刻をセット(3)
09      storage.setItem('lastAccessed', current);
10      storage.lastAccessed2 = current;
11      storage['lastAccessed3'] = current;
12    }
13  }
14);

ストレージは新しい機能なので、利用する前にまず、ブラウザが対応しているかをチェックしなければなりません。これを行っているのが(1)です。

localStorage(正確にはwindow.localStorage)は、ローカルストレージにアクセスするためのプロパティです。(1)ではlocalStorageプロパティにアクセスしてみて、アクセスできればストレージに対応していると判断し、以降の処理を行っているわけです(第1回第2回にも登場した「機能テスト」です)。

ストレージを利用する際は、最初にlocalStorageプロパティの値(localStorageオブジェクト)を変数storageに格納しておくと良いでしょう(2)。これによって、あとから格納先のストレージが変更になった場合にも、コード全体に影響が及ばなくなります。

もしもセッションストレージを利用するならば、6行目を以下のように差し替えてください。以降のデータの出し入れは、ローカルストレージ/セッションストレージに関わらず、同じ要領で行えます。

var storage = sessionStorage;

ストレージにデータを保存しているのは、(3)の箇所です。3種類の記法について、それぞれ確認しておきましょう。

表3:ストレージにデータを保存する方法

記法 構文
setItemメソッド storage.setItem(名前, 値)
プロパティ構文 storage.名前 = 値
ハッシュ構文 storage[名前] = 値

いずれの方法を利用しても構いませんが、同じアプリの中では同じ記法で統一するのが可読性という意味で望ましいでしょう。

名前は、原則としてJavaScriptの識別子のルールに沿うようにしてください。setItemメソッド、ハッシュ構文では自由な名前指定が可能ですが、名前によってはプロパティ構文でアクセスできないものが出てしまうためです。

また、ストレージは同じオリジンの中で共有されます。それは、アプリが大規模になれば、それだけ名前重複の危険が増えるということです。それを踏まえて、一般的な変数よりも具体的な名前を付けるよう意識してください。

TIPS 035:ストレージのデータを取得する

ストレージから保存済みのデータを取り出してみましょう。サンプルを実行するにあたっては、あらかじめ前のTIPSのサンプル(set.html)を実行しておいてください。

[リスト02]ストレージからキーlastAccessedのデータを取り出すコード(get.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    // ストレージが利用できるかをチェック
04    if (localStorage) {
05      // ローカルストレージをセット
06      var storage = localStorage;
07      // ストレージからキーlastAccessedを取得
08      window.alert(storage.getItem('lastAccessed'));
09      window.alert(storage.lastAccessed2);
10      window.alert(storage['lastAccessed3']);
11    }
12  }
13);
図1:ストレージに保存されたデータをダイアログに表示

ストレージからデータを取得するにも、設定の場合と同じく3種類の記法を利用できます。

表4:ストレージからデータを取得する方法

記法 構文
getItemメソッド storage.getItem(名前)
プロパティ構文 変数 = storage.名前
ハッシュ構文 変数 = storage[名前]

TIPS 036:ストレージのデータをツールから確認する

ストレージのデータは、ブラウザのツールを利用して確認することもできます。開発に際しては、いちいちコードを記述するのではなく、ツールを活用することでストレージの内容を確認しながら作業することで、効率も高められるでしょう。

以下では、Chrome、Firefox、Safari、Opera環境での確認方法を紹介します。執筆時点では、Internet Explorerでストレージの内容を確認することはできません。

(1)Google Chrome(8以降)

メニューバーの (Google Chromeの設定)ボタンから[ツール]-[デベロッパーツール]を起動します。その[Resource]タブを開き、左ツリーから[Local Storage](または[Session Storage])-[<IPアドレス、またはlocalhost>]を選択してください。
図2:デベロッパーツール(Google Chrome)(クリックで拡大)

リストの該当する行で右クリックし、コンテキストメニューから[Edit][Delete]を選択することで、既存のデータを編集できます。また、何もない行でコンテキストメニューの[Add New]を選択すれば、新規のデータを追加することも可能です。

(2)Firefox

FirefoxではFirebugアドオンが必要です。Firebugを起動し、上のツールバーから[DOM]タブを開き、[window]の下にある[Local Storage](または[Session Storage])を選択してください。

図3:デベロッパーツール(Firefox)(クリックで拡大)

リストの該当する行で右クリックし、コンテキストメニューから[プロパティを編集...][プロパティを削除]を選択することで、既存のデータを編集できます。

(3)Safari(5以降)

画面右上の[一般設定のメニュー]ボタンから[設定]をクリックして、[詳細]ダイアログを表示します。[詳細]タブを開き、[メニューバーに"開発"メニューを表示]にチェックを入れてダイアログを閉じます。画面右上の[現在のページのメニュー]ボタンから[開発]-[Web インスペクタを表示]をクリックします。[リソース]タブを開き、左ツリーから[Local Storage](または[Session Storage])-[<IPアドレス、またはlocalhost>]を選択してください。

図4:デベロッパーツール(Safari)(クリックで拡大)

リストの該当する行で右クリックし、コンテキストメニューから[編集][削除]を選択することで、既存のデータを編集できます。また、何もない行でコンテキストメニューの[新規を追加]を選択すれば、新規のデータを追加することも可能です。

(4)Opera(12以降)

[表示]メニューから[開発者用ツール]-[Opera Dragonfly]を起動します。[ストレージ]タブを開き、そのタブの下のバーから[ローカル ストレージ](または[セッション ストレージ]を選択してください。

図5:デベロッパーツール(Opera)(クリックで拡大)

リストの該当する行で右クリックし、コンテキストメニューから[アイテムを編集][アイテムを削除]を選択することで、既存のデータを編集できます。また、何もない行でコンテキストメニューの[アイテムを追加]を選択すれば、新規のデータを追加することも可能です。

TIPS 037:ストレージからすべてのデータを取り出す

ストレージからすべてのデータを取り出すには、以下のようなコードを書きます。

[リスト03]ストレージ内のすべてのデータをリスト化するコード(length.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    if (localStorage) {
04      var storage = localStorage;
05 
06      // ストレージの内容を列挙するshow関数を定義
07      var show = function() {
08        var str = '<table>';
09        // ストレージの内容を順番に取り出し、リストに整形(1)
10        for (var i = 0; i < storage.length; i++) {
11          // i番目のキーを取得(2)
12          var k = storage.key(i);
13          str += '<tr><th>' + k + '</th>';
14          // 指定されたキーの値を取得(3)
15          str += '<td>' + storage.getItem(k) + '</th></tr>';
16        }
17        str += '</table>';
18        // 整形したテーブルをページに反映
19        document.querySelector('#result').innerHTML = str;
20      };
21      // show関数を呼び出し
22      show();
23      ...中略...
24    }
25  }
26);
27...中略...
28<table id="result"></table>
図6:ストレージの内容をテーブルに列挙

lengthプロパティ(1)は、ストレージに保存されているデータの個数を表します。ここでは、forブロックを利用して0~storage.length - 1個目のデータをストレージから取り出しています。

i番目のデータのキー(名前)を取得するにはkeyメソッドを利用します(2)。キー名が取得できてしまえば、あとはgetItemメソッドで値を取り出すだけです(3)。

TIPS 038:ストレージ上のデータを削除する

TIPS 037で作成したサンプルに、データの削除機能を追加してみましょう。

[リスト04]指定されたデータをストレージから削除するコード(length.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    if (localStorage) {
04      var storage = localStorage;
05      ...中略...
06      // [削除]ボタンクリックで該当するデータを削除
07      document.querySelector('#remove').addEventListener('click', function (e) {
08        var n = document.querySelector('#name');
09        // テキストボックスで指定されたキーを削除(1)
10        storage.removeItem(n.value);
11        show();   // テーブルを再描画
12      });
13 
14      // [クリア]ボタンクリックですべてのデータを削除
15      document.querySelector('#clear').addEventListener('click', function (e) {
16        // データをクリア(2)
17        storage.clear();
18        show();   // テーブルを再描画
19      });
20    }
21  }
22);
23...中略...
24<div class="container">
25  <label for="name">名前:</label>
26  <input id="name" type="text" value="" />
27</div>
28<div class="container">
29  <input id="remove" type="button" value="削除" />
30  <input id="clear" type="button" value="クリア" />
31</div>
32<table id="result"></table>
図7:指定のデータを削除(クリックで拡大)

指定されたデータを削除するには、removeItemメソッドを利用します。

[構文]removeItemメソッド

  • removeItem(名前)

すべてのデータをまとめてクリアするならば、clearメソッドを利用します。

[構文]clearメソッド

  • clear()

ただし、冒頭述べたようにストレージはオリジン単位に管理されます。ひとつのオリジンで複数のアプリを運用している場合などに、誤って他のアプリで利用しているデータまで削除してしまわないように注意してください。

TIPS 039:ストレージにオブジェクトを出し入れする

現在のブラウザでストレージに保存できるのは、文字列だけです。仕様の上ではストレージにはオブジェクトも格納できることになっていますが、現時点でこれに対応しているブラウザはありませんので注意してください。
オブジェクトを指定してもエラーにはなりませんが、toStringメソッドで内部的に文字列化された結果、まったく意味のないものになってしまうのです。

図8:ストレージにオブジェクトを保存した場合(デベロッパーツールで確認)(クリックで拡大)

そこで、オブジェクトをストレージに保存する場合には、以下のようなコードを書く必要があります。

[リスト05]ストレージにオブジェクトを保存するためのコード(obj.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    if (localStorage) {
04      var storage = localStorage;
05      // オブジェクトを準備
06      var data1 = { name: '山田リオ', age: 5, favorite: 'ドラえもん' };
07      // ストレージに保存(1)
08      storage.setItem('data', JSON.stringify(data1));
09      // ストレージからデータを取得(2)
10      var data2 = JSON.parse(storage.getItem('data'));
11      // nameプロパティの内容を表示(3)
12      window.alert(data2.name);
13    }
14  }
15);
図9:オブジェクトのnameプロパティが正しくダイアログ表示できた

JSON.stringifyメソッドを利用することで、オブジェクトをJSON(*)という文字列の形式に変換できます(1)。

[構文]stringifyメソッド

  • JSON.stringify(オブジェクト)

*)JavaScript Object Notation。JavaScriptのオブジェクトを表すための記法。Ajax技術などでよく利用される。

例えばサンプルの例であれば、以下のような文字列が生成されます。

{"name":"山田リオ","age":5,"favorite":"ドラえもん"}

文字列にしてしまえば、あとはこれまでと同じくsetItemメソッドなどで保存が可能です。

ただし、getItemメソッドでデータを取り出した時には注意が必要です(2)。というのも、そのままでは文字列ですので、これをオブジェクトに再変換する必要があるのです。これを行うのが、JSON.parseメソッドです。

[構文]parseメソッド

  • JSON.parse(文字列)

変換された結果、「data2.name」のようにオブジェクトとして配下のプロパティにもアクセスできることが確認できます(3)。

TIPS 040:ストレージの登録/更新/削除を監視する

ストレージで登録/更新/削除などなんらかの操作が行われた場合、storageというイベントが発生します。これを利用することで、ストレージの変化に対して処理を実行するようなコードを記述できます。

なお、storageイベントは現在のページからの操作では発生しない場合があるようです(あくまで自分とは別のところでストレージが操作されたことを検出するためのしくみだからです)。サンプルを確認する場合は、event.htmlを起動した状態で、set.htmlを実行してください。

[リスト06]ストレージが変化した時にその結果を表示するコード(event.html)

01window.addEventListener('DOMContentLoaded',
02  function() {
03    if (localStorage) {
04      // ストレージが変更された時に実行するコード
05      window.addEventListener('storage', function (e) {
06        // イベント発生時の情報をページに反映
07        document.querySelector('#key').innerHTML = e.key;
08        document.querySelector('#old').innerHTML = e.oldValue;
09        document.querySelector('#new').innerHTML = e.newValue;
10        document.querySelector('#url').innerHTML = e.url;
11      }, false);
12    }
13  }
14);
図10:ストレージへの変更内容がページに反映された

storageイベントリスナの中では、イベントオブジェクトeを介して、以下のような情報にアクセスできます。

表5:イベントオブジェクトで取得できる情報

プロパティ 概要
key イベント発生の原因となったキー
newValue 変更後の値(登録/更新時)
oldValue 変更前の値(更新/削除時)
url 発生元のURL
storageArea ストレージの種類(sessionStorage/localStorageオブジェクト)
  • ブラウザ標準ストレージWeb Storageを使ったサンプル

著者
山田 祥寛(YAMADA, Yoshihiro)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています