状態を管理する、その状態に応じて条件分岐するやり方。
目次
フラグをビットで管理するメリットとケース
特定の条件でのみリマーケティングタグを発火する、イベントをカウントするなど、何らかの処理をすることがある。
「3回目の訪問で、詳細ページを閲覧済みで、未購入のユーザに対して広告配信をしたい」
というケースなど、条件が複雑になると広告配信プラットフォームのタグと管理画面だけでは実現不可能で、JavaScriptとcookieを使う必要がある。
個別の条件を満たしたときにJavaScriptで条件判定をし、フラグを立てる。
その結果をcookieに保存する。
cookieに保存されたフラグの組み合わせを参照して、すべての条件を満たしていたら特定のタグを発火する。
ということで、状態のフラグ(3回目の訪問かどうか、詳細ページを見たことがあるかどうか、未購入かどうか)を管理することになる。
単純に1フラグを1cookie変数とするとcookieで管理する変数の数が多くなってしまう。
そこで1個の変数でこれらの状態をまとめて管理する方法がビットによる管理である。
なおこの考え方はJavaScriptに限らずあらゆるプログラム言語で実装が可能。
管理するフラグが多く、メモリ消費や発生するパケットを小さくする必要があるときに重要となる。
ビット
ビットは0または1の2値を表す情報の単位
それを8個つなげたもの、
11001101
は8個の0/1を表す情報を保持している。
11001101
の各桁は0か1しかないので2進数として見ることができる。
これを10進数に置き換えると205ということになる。
8ビットの変数1個(0~255の整数)であれば8個のビット(0/1)が収まる。
つまり0~255の整数で8種類の0/1の状態を表せる。
この最小の情報の単位であるビットに対する処理がビット処理である。
フラグの定義
var STATE = {
'DISABLED': 1<<0,
'HOVER': 1<<1,
'ACTIVE': 1<<2
};
1<<桁
で、桁は0からスタート
フラグを設定(代入)する
まず状態を表す変数を宣言
let state
フラグDISABLED
を立てる
state |= STATE.DISABLED
フラグDISABLED
とHOVER
を同時に立てる(一度に代入する)
state |= STATE.DISABLED | STATE.HOVER
フラグのセットを作る
state = STATE.DISABLED | STATE.HOVER | STATE.ACTIVE
フラグDISABLED
を下げる
state &= ~STATE.DISABLED
フラグを下げる場合は「&
」にするのと否定の「~
」を付ける
フラグDISABLED
とHOVER
を同時に下げる(一度に代入する)
state &= ~(STATE.DISABLED | STATE.HOVER);
特定のフラグを反転させる
state ^= STATE.DISABLED;
特定のフラグを取り出す
state
の中でDISABLED
に対応するビットの値を抜き出す(これが0でなければDISABLED
のフラグが立っていることになる)
state & STATE.DISABLED
state
の中でDISABLED
、HOVER
に対応する部分を抜き出す
state & (STATE.DISABLED | STATE.HOVER)
- これが0でなければ
DISABLED
またはHOVER
のフラグが立っていることになる - これが
(STATE.DISABLED | STATE.HOVER)
と等しい場合、DISABLED
とHOVER
の両フラグが立っていることになる
フラグの取り出しは条件判定で使うことになる。
逆引き
やりたいこと | 演算方法 | 演算子 | 変更したいビット | そのままにしたいビット |
---|---|---|---|---|
ビットをすべて反転させたい | NOT | ~ | すべて変更される | 指定不可 |
一部のビットを反転させたい | XOR | ^ | 反転させたいビット: 1 | 0 |
一部のビットをONにしたい | OR | | | ONにしたいビット: 1 | 0 |
一部のビットをOFFにしたい | AND | & | OFFにしたいビット: 0 | 1 |
https://codeiq.jp/magazine/2014/03/6558/
条件判定
if(state & STATE.DISABLED) { 処理 }
if(state & (STATE.DISABLED | STATE.HOVER)) { 処理 }
!!(state & STATE.DISABLED) && 処理
ビットを使った条件
// cookie処理ライブラリ
var _cookie = {
set: function(cname, cvalue, exdays, path) {
var strCookie = cname + '=' + cvalue;
if (typeof exdays != 'undefined') {
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
strCookie += '; expires=' + d.toUTCString();
}
strCookie += typeof path != 'undefined' ? '; path=' + path : '; path=/'
document.cookie = strCookie;
},
get: function(cname) {
var name = cname + '=';
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return '';
}
};
// ここから処理
var p = location.pathname;
var FLAGS = {
HOME: 1<<0,
CAR_TOYOTA: 1<<1,
CAR_NISSAN: 1<<2,
TAG_FIRED: 1<<3
};
var flags = parseInt(_cookie.get('pageview_state') || 0);
/^\/(index\.html)?$/.test(p) && (flags |= FLAGS.HOME);
p.indexOf('/toyota/car/') == 0 && (flags |= FLAGS.LIST_TOYOTA);
p.indexOf('/nissan/car/') == 0 && (flags |= FLAGS.LIST_NISSAN);
// トップページを閲覧したことがなく、日産かトヨタの車を見たことがある、かつタグ発火したことがない
if (!(flags & FLAGS.HOME) && (!!(flags & FLAGS.TOYOTA) || !!(flags & FLAGS.NISSAN)) && !(flags & FLAGS.TAG_FIRED)) {
console.log('Fire a tag!');
flags |= FLAGS.TAG_FIRED;
}
_cookie.set('pageview_state', flags);
参考
- 基本をわかりやすく
- 簡単にまとめ
- JavaScriptの場合の詳細
計測実装 の記事一覧