准备知识
2进制和16进制
- 0x开头是16进制
0x2000000
- 0b开头是2进制
export const Deletion = 0b00000000000000001000;
进制转换
数字转换成字符串
numObj.toString([radix])
- 十进制转换成二进制
var num=100;
num.toString(2); // "1100100"
解析一个字符串并返回指定基数的十进制整数
Number.parseInt(string[, radix])
- 16进制转换成十进制
var num=2000000;
parseInt(num,16); // 33554432
计算
&:按位与
var a = 0b100;
var b = 0b1100;
var res = a & b;
console.log(res.toString(2));// 100
|:按位或
var a = 0x100;
var b = 0x2000;
var res = a | b;
console.log(res.toString(16));// 2100
应用场景
描述
用于表示各种状态的叠加态。
通常解法
通俗一点说,今天吃的水果沙拉有西瓜、芒果、草莓。
那用js怎么表示这样的状态呢?通常情况我们肯定是使用数组:
var watermelon = '1';
var mango = '2';
var strawberry = '3';
var salad = [watermelon, mango, strawberry];
判读沙拉里是否有芒果
salad.includes(mango);
这样有啥问题吗?
又不是不能用,倒也没啥大的问题。但是对于一段高频代码来说,使用数组反复做push、pop、includes这种操作只是为了维护某个状态,并不是最优解。
位运算解法
flags
在React中有这样的应用。
fiber
可以理解为React中虚拟Dom节点,使用fiber.flags
来描述该节点要执行DOM操作的具体类型。
/* react/packages/react-reconciler/src/ReactFiberFlags.js */
// DOM需要插入到页面中
export const Placement = /* */ 0b00000000000000000010;
// DOM需要更新
export const Update = /* */ 0b00000000000000000100;
// DOM需要插入页面中并更新
export const PlacementAndUpdate = /* */ Placement | Update;
// DOM需要删除
export const Deletion = /* */ 0b00000000000000001000;
bitField
bluebird中对于promise状态的部分描述如下
/* bluebird-master/src/constants.js */
CONSTANT(IS_FULFILLED, 0x2000000|0);
CONSTANT(IS_REJECTED, 0x1000000|0);
CONSTANT(WILL_BE_CANCELLED, 0x800000|0);
CONSTANT(IS_FINAL, 0x400000|0);
CONSTANT(IS_BOUND, 0x200000|0);
/* bluebird-master/src/promise.js */
Promise.prototype._setFulfilled = function () {
this._bitField = this._bitField | IS_FULFILLED;
this._fireEvent("promiseFulfilled", this);
};
Promise.prototype._isFollowing = function () {
return (this._bitField & IS_FOLLOWING) === IS_FOLLOWING;
};
状态判定
水果沙拉位运算应用
观察上面的例子,可以把数组解法改成这样
var watermelon = 0b001;
var mango = 0b010;
var strawberry = 0b100;
var salad = watermelon| mango|strawberry;
var res = (salad & mango) === mango;
console.log(res); // true
最大整数范围
js中能表示的最大整数为2^53
所以使用这个方法按每个状态只有一个1来算,能存53个状态。
THE END