document.cookieは便利なのですが、たまにどうしようもなく不便に感じるときがあります。localStorageに全部置き換えられるなら、そうしてしまいたい時も年に一度ぐらいは。
js側からcookieを操作するときに大体の場合は$.cookie
かまたはその類似のものを使っているので、そちらを操作してもなんとかなるとは思いますが、せっかくなのでES5で入った機能を使います。
Object.defineProperty
Object.definePropertyを使うと既存のオブジェクトに対して、getterとsetterを追加できます。現在の主要なブラウザではほとんどサポートされているようです
しかし、document.cookieは特別なObjectの一つです。definePropertyが使えるのかと思って調べてみたのですが、やってみると案外と出来ました。以下のコードをデベロッパーツールで実行してみてください。
Object.defineProperty(document, "cookie", {
get: function () {
console.log("getter");
},
set: function (cookie) {
console.log("setter");
}
});
> document.cookie
getter
> document.cookie="test=1"
setter
Mac上のChrome 47, Firefox 43では動作することは確認できましたが、他のブラウザでは動かない可能性があります。
事前準備ができたのでlocalStorageと組み合わせてdocument.cookie
の操作をハックします。
コード
Object.defineProperty(document, "cookie", {
get: function () {
var cookies = JSON.parse(localStorage.getItem('cookies'));
if (!cookies) {return "";}
var strs = [];
for(var key in cookies){
strs.push(cookies[key]);
}
return strs.join(";");
},
set: function (cookie) {
// console.log(cookie);
var cookies = JSON.parse(localStorage.getItem('cookies')) || {};
var key = cookie.match(/^[^=]+/);
cookies[key] = cookie;
localStorage.setItem('cookies', JSON.stringify(cookies));
}
});
結果
> document.cookie
""
> document.cookie="test1=1"
"test1=1"
> document.cookie="test2=2"
"test2=2"
> document.cookie
"test1=1;test2=2"
> localStorage["cookies"]
"{"test1":"test1=1","test2":"test2=2"}"
対応できていないこと
上記の例では以下のものに対応していません。対応が難しそうなものほど下になっています。
- 2つ以上の値を同時に設定すること
- path
- expire, max-age
- サーバとの送受信
- secure
- domain
- httpOnly
domainやhttpOnlyの挙動をjsで対応するのは難しいですね。httpOnlyは振る舞いだけなら実装できますが、値をjsから取得できないという部分を満たせません。js部分の実装時にその2つを明示的に設定しているケースは、あまりないとは思いますが。
サーバとの送受信時の処理は、Service Workerでプロキシすることで出来るのではないかとは考えていますが未検証です。
またSafariのprivate modeではlocalStorageが動作しない問題がまだ残っているようなので、cookieの情報がないと動かないといった場合には向いていません。