uhyohyo.net

JavaScript初級者から中級者になろう

十四章第一回 Storage

このページの最終更新日:

今回紹介するStorageはとても便利なものです。Storageとは何かというと、簡単にいうとブラウザにデータを保存しておけるものです。そういうと昔からあるCookieを思い出す人も多いと思います。Cookieとの違いは、「データがサーバーへ送られるか送られないか」です。Cookieはブラウザに保存されており、サーバーへのリクエストの際はCookieが送られます。サーバー側はそれを参照して動作を変えることができます。

一方、Storageはサーバー側からは参照できません。Storageを見ることができるのはJavaScriptからのみです。つまり、Cookieとは異なり完全にクライアント側で動作するJavaScriptプログラム向けに記憶機能が提供されているということです。基本的にはこちらのほうが便利なので、サーバーに送る必要がないデータを保存しておきたいときはStorageを使うのがよいでしょう。

2つのStorage

Storageには2種類あります。一つはlocalStorageであり、もうひとつはsessionStorageです。この2つでは、データの保存のされ方が違うため用途も違います。

windowはlocalStoragesessionStorageというプロパティを持っており、これを通じて利用可能です。

この2種類のうちでは、localStorageのほうが使用される頻度が圧倒的に多いようです。localStorageは、同じオリジンの間で共有されるストレージです。これは前章でおなじみの同一オリジンポリシーを考えれば分かりますね。違うオリジンのデータを読めるべきではありません。ポイントは、localStorageは同じオリジンなら、違うページからでも同じ内容を共有できるということです。複数のページの連携にも使うことができるでしょう。

これを利用して、サイトを利用したデータをずっと保存しておくことが可能です。ただしもちろん、ユーザーが消そうと思えばデータは消すことができます。

次のsessionStorageは少し毛色が違います。これはブラウジングコンテキスト1つに対して1つの領域が割り当てられます。つまり、異なるブラウジングコンテキストからは違うsessionStorageになり、保存内容が共有されないということです。ブラウジングコンテキストは前章でも出てきましたね。要するにブラウザのタブ1つということです。異なるタブでは異なるsessionStorageになります。

それでは、具体的な使い方を見て行きましょう。

Storageの操作

Storageの操作は、localStorageでもsessionStorageでも変わりません。基本は、Storageのプロパティに値を入れるとそれがそのまま保存されます。実は、保存できる値は文字列に限ります。オブジェクトとかを保存したい場合はJSONにしましょう。

例えば、localStorageに"foo"という名前で"bar"という値を保存したい場合はこうです。


localStorage.foo="bar";

簡単ですね。ただし、setItemというメソッドを使うことも可能です。


localStorage.setItem("foo","bar");

このとき、データに付けられる名前はキーと呼ばれます。上の例の場合は"foo"がキーですね。

Storageに保存されている値を得るにはプロパティを参照します。


console.log(localStorage.foo);

setItemと対になる、getItemというメソッドも使えます。


console.log(localStorage.getItem("foo"));

基本的な保存と取り出しは以上です。また、保存されたデータを消去するにはremoveItemメソッドです。


localStorage.removeItem("foo");

また、そのStorageのデータを全て消去するclearメソッド(引数無し)があります。

さらに、そのStorageにデータが何個保存されているか示すlengthプロパティがあります。例えば上の例の場合、"foo""bar"という値が保存されているだけとするとlengthは1です。

そして、lengthがあるということは、0から順番にデータを取得できそうですね。Storageの場合はkeyというメソッドを使います。これは番号を渡すとキーを返します。たとえば、こんな感じです。


var key=localStorage.key(0);	//0番目のキーを取得
console.log("0番目のキーは"+key+"で 値は"+localStorage[key]+"です");

以上でStorageの操作は終了です。上の例はlocalStorageでしたが、sessionStorageも使い方は全く同じです。

Storageのイベント

Storageに関して、Storageが変更されたときにそれを知らせるイベントがあります。それがstorageイベントです。これは、popStateとかと同様、windowにおいて発生するイベントです。すなわちこうです。


window.addEventListener("storage",function(e){
},false);

このstorageイベントにおけるイベントオブジェクトはStorageEventのインスタンスであり、以下のプロパティを持っています。

key
変更されたキーの名前。
oldValue
変更前の値。
newValue
変更後の値。
url
ストレージが変更されたページのURL。
storageArea
変更が起こったStorageオブジェクト(localStorageまたはsessionStorage)。

ちょっと注目したいのがurlプロパティですね。実は、同じStorageを共有している(といってもsessionStorageを複数タブで共有することはないのでlocalStorageになりますが)複数のブラウジングコンテキスト(≒タブ)において、そのStorageが変更されると全てのタブでstorageイベントが発生します。つまり、他のタブでlocalStorageに行われた変更を即座に感知できるということです。

しかも、localStorageを変更した張本人のタブではstorageイベントは発生しません。これは、いちいちstorageイベントを捕捉しなくても変更タイミングが明らかだからでしょうか。

これはブラウジングコンテキスト間の非常に簡単な通信と見ることもできますね。ということで、使う機会があるかもしれませんので紹介します。

Storageに対してどんな操作が行われたかによって、key,oldValue,newValueの値が変わります。基本的にはkeyは変更されたキー、oldValueは変更前の値、newValueは変更後の値です。

たとえば単純に新しいキーに書き込んだ場合、またはすでにあるキーの値を書き換えた場合には、keyはそのキー、oldValueは変更前の値(何も入っていなかったならnull)、newValueは新しくセットした値になります。

なお、getItemなどは見るだけなのでイベントは起こりません。

次にremoveItemは、key,oldValueはsetItemと同じですが、newValueがnullになっています。

clearメソッドの場合は、key,oldValue,newValueが全てnullになっています。

Storageのサンプル

サンプルを用意しました。ページを開くたびにlocalStorageを読んで1を足して、ページの表示関数をカウントするやつです。当然ながら、localStorageは各利用者のブラウザに保存されるものであり、サーバーに保存されるカウンタではないので他人の訪問は記録されませんし見ることもできません。

ページを開いて更新すると数が増えます。localStorageに保存された内容は、ページを更新しても残っているからです。また、ページを閉じてから開きなおしても前回のデータが残っていて、続きからカウントされます。

ソースは以下のようになっています。


//ページ表示時にカウントを1ふやす
var value=localStorage.sample14_1;
if(!value){
  //valueに何も入っていなかったら
  value=1;
}else{
  value=parseInt(value)+1;
}
localStorage.sample14_1=value;
disp(value);

//他のページでlocalStorageが更新されたら反映する
window.addEventListener("storage",function(e){
  if(e.key=="sample14_1"){
    //sample14_1が更新された
    disp(e.newValue);
  }
},false);

function disp(val){
  document.getElementById('result').textContent="あなたは"+val+"回目の訪問です";
}

sample14_1というキーにデータを保存していることが分かります。前半は変数valueにlocalStorageのデータを読み込み、1を足してそれをdisp関数で表示しています。その後それをlocalStorageに保存しています。ただし、始めてのときは何も入っていないので、valueを1としています。

valueに1を足す際、Storage内のデータは文字列なのでparseIntで数値に変換している点に注意して下さい。

このページを何度も開きなおすと数字が増えていきます。もちろんこれはlocalStorageにデータが保存されているからですね。

サンプルの後半部分はstorageイベントを使っています。sample14_1が更新されたらその内容を表示しなおしています。

storageイベントをこのサンプルで確認してみましょう。複数タブでこのサンプルを開き、更新するなどしてカウントを増やしてみて下さい。もう一つのほうにもstorageイベントによって変更が伝えられ、常に表示が一緒になっているはずです。

また、sessionStorageの動作を用意するために、サンプル2を用意しました。これは上のサンプルと同じことをsessionStorageで行なっています。ただし、さっき解説した通り異なるタブだと異なるsessionStorageになるので、storageイベントの部分は消しています。

サンプル2を開いて「ページの更新」を行うと回数が増えます。これは、同じタブならばページを移動・更新してもsessionStorageは一緒だからです。

一方、今度は複数のタブを開いても、表示は一致しません。また、各々のタブで更新を行うと別々にカウントが進みます。これは、タブが違うとsessionStorageが違うからです。このような違いを理解して使用しましょう。今のサンプルでわかるように、sessionStorageはその名の通り、現在の作業の内容を一時的に保存しておくようなそういう用途が合っているかもしれません。localStorageはサイト利用の情報としてずっと保存しておきたいような情報を入れるといいでしょう。