JavaScript のビットマスクをはじめて使った。というかビット演算子というものに触れるのがそもそもはじめて。最初は何が何やらわからなかったけど、以下のページなどを参考にしつつなんとかやってみた。

状況としては、ユーザー設定のフラグをビットマスクで管理していて、それを API を通じて GET/POST する、という感じ。ここでは例として、アプリケーションのユーザー設定で、各種ソーシャル系サービスと連携するかどうかみたいなデータを管理する場合を想定する。

まず、各フラグのデータを 1、2、4、8… という整数値で定義しておく。こういったデータは定数として扱うのでキーを大文字にすることが多い、らしい。

var social = {
        TWITTER:     1,
        FACEBOOK:    2,
        GOOGLE_PLUS: 4,
        TUMBLR:      8
    };

HTML ではこれらのフラグに対応したチェックボックスを用意し、カスタムデータ属性でフラグの値を埋め込む。これは Underscore.js のテンプレートを使った例で、<%= ... %> の部分が数値に置き換わって出力される。

<label>
    <input type="checkbox" data-flag="<%= social.TWITTER %>">
    Twitter
</label>
<label>
    <input type="checkbox" data-flag="<%= social.FACEBOOK %>">
    Facebook
</label>
<label>
    <input type="checkbox" data-flag="<%= social.GOOGLE_PLUS %>">
    Google+
</label>
<label>
    <input type="checkbox" data-flag="<%= social.TUMBLR %>">
    Tumblr
</label>

テンプレートがロードされたら、API から取得したフラグと各チェックボックスのカスタムデータ属性の値を & 演算子で判定し、アリなら checked にする。この例では 1 つ目と 4 つ目がオンになる。

var flags = 9; // API から取得したフラグ
$('input[type="checkbox"]').each(function () {
    $(this).attr('checked', !!(flags & $(this).data('flag')));
});

データを POST するときは、オンになってるチェックボックスを抜き出して、| 演算子でフラグを立てる (という言い方でいいんだろうか?)。なんかループしなくてもできるやり方がありそうな予感がするけど思いつかない。

var flags = 0;
$('input[type="checkbox"]:checked').each(function () {
    flags |= $(this).data('flag');
});

ビット演算子、『サイ本』では 1 ページ半ほどの扱いで「読み飛ばしても問題ありません」って言ってるし、『The Good Parts』だと「悪いパーツ」に入ってるし、まったく意識したこともなかったけど、やっぱ使うときは使いますね。たしかに一見して何をやってるかわかんなくて、どうやら動いてるもののいまいち不安。結果、「考えた人頭いいなー」といういつもの馬鹿みたいな感想が浮かびました。