uhyohyo.net

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

十四章第一回 Storage

今回紹介するStorageはとても便利なものです。Storageとは何かというと、簡単にいうとブラウザにデータを保存しておけるものです。そういうと昔からあるCookieを思い出す人も多いとおもいます。Cookieとの違いは、「データがサーバーへ送られるか送られないか」です。Cookieは、CGIとかではよく使われています。サーバー側から参照できるからです。

ところがStorageはサーバー側からは参照できません。つまり、JavaScriptからのみ参照できるということです。基本的にはこちらのほうが便利だと思いますが、サーバーにも送りたいときはCookieを送るなど、場合に応じて活用しましょう。

2つのStorage

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

これはそれぞれ同名の、localStorage,sessionStorageという変数から利用可能です。

localStorageは、同じオリジンの間で共有されるストレージです。オリジンとは十三章第一回で紹介したもので、概ね「ドメインが同じなら同じサイトとみなされるのでOK」ということです。

これを利用して、サイトを利用したデータをずっとセーブしておくことが可能です。ただしもちろん、ユーザーが消そうと思えばデータは消すことができます。またさっき述べたとおり、他のオリジンのlocalStorageは参照できないので安心です。

次のsessionStorageは少し毛色が違います。これはブラウジングコンテキスト1つに対して1つの領域が割り当てられます。つまり、異なるブラウジングコンテキストからは違うsessionStorageになるということです。

ブラウジングコンテキストとは何かというと、要するにブラウザのタブ1つということです。異なるタブだと異なるsessionStorageになります。localStorageの場合は、オリジンが同じであれば他のタブの間でもデータが共有できます。あるタブでlocalStorageに保存したデータは、すぐに他のタブからも利用可能になります。

ただし、同じブラウジングコンテキストということは、そのタブ内で違うページに移動したとしてもsessionStorageは同じままということです。ただし、localStorageと同様に同オリジンの条件は課せられます。つまり、同じタブでも違うオリジンのページに移動してしまえば違うsessionStorageになるということです。

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

Storageの操作

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

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

localStorage.foo="bar";

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

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

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

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の操作は終了です。

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の値が変わってきますから、それを参考にして区別するとよいでしょう。oldValueはその名の通り変更前の値、newValueは変更後の値です。

たとえば単純にプロパティに代入(あるいはsetItemメソッドを使用)した場合には、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で数値に変換している点に注意して下さい。

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

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

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

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

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