JS位运算符
我是leon 人气:0概览
本文详细剖析JavaScript的位运算符,其涉及的计算机原理和操作效果。
然后从实战的角度出发,罗列相关的应用场景。
位操作符概览
运算符 | 描述 | 示例 |
---|---|---|
按位与(AND) | 两个操作数对应的比特位都是1时,结果才为1,否则为0 | 1011 & 0111 = 0011 |
按位或(OR) | 两个操作数对应的比特位至少有一个1时,结果为1,否则为0 | 1011 | 0111 = 1111 |
按位异或(XOR) | 两个操作数对应的比特位有且只有一个1时,结果为1,否则为0 | 1011 ^ 0111 = 1100 |
按位非(NOT) | 逐个反转操作数的比特位,即0变成1,1变成0 | ~1011 = 0100 |
左移 | 通过从右推入零向左位移,并使最左边的位脱落。 | 1011 << 1 = 10110 |
有符号右移 | 通过从左推入最左位的拷贝来向右位移,并使最右边的位脱落。 | 01011 >> 1 = 00101 |
无符号右移 | 通过从左推入零来向右位移,并使最右边的位脱落。 | 01011 >>> 1 = 00101 |
位操作支持多少位?
js只支持32位二进制数的位操作,也即能处理的最大十进制数字是 4294967295
。
parseInt('11111111111111111111111111111111', 2); // 4294967295
验证下超过32位二进制数的位操作:
// 33位二进制数,得到十进制数字 8589934591 parseInt('111111111111111111111111111111111', 2); // 8589934591 // 对数字进行无符号位右移 8589934591 >>> 0; // 4294967295 4294967295 >>> 0; // 4294967295
可以看出,数字 8589934591
和 4294967295
进行 无符号位右移0位
操作,得到的结果是一样的。
产生这样结果的原因,是js的位操作实现,只支持32位
。
注意:
ECMAScript
中的所有数值都以IEEE754
64位格式存储,只是在位操作的时候 ,需要转换成32位进行操作。
负数的无符号右移
-2 >>> 1
为什么输出2147483647
?
-2
在运算中,是用补码表示,即1 1111111111111111111111111111110
。
其中,第1位是符号位。 符号位1
代表当前数字是负数。
将-2
无符号右移1位,则最右边的0
脱落,剩下31位1111111111111111111111111111111
,接着,在左侧补0
,得到01111111111111111111111111111111
。
01111111111111111111111111111111
代表十进制数2147483647
。
状态控制
场景:
以下使用React
+TypeScript
,实现游戏状态机的状态流转,根据状态渲染对应的操作按钮。
// 游戏状态定义 export enum GAME_STATE{ INIT = 1 << 0, // 二进制表示:00001 JOIN = 1 << 1, // 二进制表示:00010 PREPARE = 1 << 2, // 二进制表示:00100 PLAY = 1 << 3, // 二进制表示:01000 }
// 根据状态渲染按钮 function RenderButton({state, changeState}){ if((state & GAME_STATE.PLAY) === GAME_STATE.PLAY){ return null; } if((state & GAME_STATE.INIT) === GAME_STATE.INIT){ return <button onClick={() => changeState(GAME_STATE.JOIN)} >加入游戏</button> } if((state & GAME_STATE.JOIN) === GAME_STATE.JOIN){ return <button onClick={() => changeState(GAME_STATE.PREPARE)} >准备游戏</button> } if((state & GAME_STATE.PREPARE) === GAME_STATE.PREPARE){ return <button onClick={() => changeState(GAME_STATE.PLAY)} >开始游戏</button> } return null; } // 渲染游戏页面 function Page(){ const state = useRef(GAME_STATE.INIT); const changeState = useCallback((newState) => { state.current = newState; }, [state]); return (<div> // ....other code <RenderButton state={state.current} changeState={changeState} /> </div>); }
权限控制
设计一个权限控制,用于不同角色对网站文章的权限分配。
export enum ARTICLE_RULE{ VIEW = 1 << 0, // 查看文章 EDIT = 1 << 1, // 编辑文章 PUBLISH = 1 << 2, // 发布文章 DELETE = 1 << 3, // 删除文章 } export enum ROLE{ GUEST = ARTICLE_RULE.VIEW, // 访客 ADMIN = ARTICLE_RULE.VIEW | ARTICLE_RULE.EDIT | ARTICLE_RULE.PUBLISH | ARTICLE_RULE.DELETE, // 超级管理员 OPERATOR = ARTICLE_RULE.VIEW | ARTICLE_RULE.EDIT | ARTICLE_RULE.PUBLISH, // 运营 }
if(user.role === 'admin'){ console.log("user拥有admin权限"); user.rule = ROLE.ADMIN; // 赋予角色权限 } if((user.rule & ARTICLE_RULE.DELETE) === ARTICLE_RULE.DELETE){ console.log("user拥有删除文章权限"); }
判断奇偶数
奇数,最末尾1位,一定是1
。
所以将数字与1
(二进制表示为:00000000000000000000000000000001
)作位操作&
。
如果等于1
,则是奇数。
function isOdd(number){ return number & 1 === 1; }
交换两个变量的值
let a = 1; let b = 2; a = a ^ b; // 这一步,a缓存了 a ^ b 的结果 b = a ^ b; // 等价为: b = a ^ b ^ b, 其中 b ^ b = 0; 所以 b = a ^ 0 = a a = a ^ b; // 同上
判断整数是否相等
function isEqual(number1, number2){ return (number1 ^ number2) === 0; }
判断是否为负数
如果是负数,则对数字进行 无符号右移
位操作,会变成一个新的数字。
所以,如果是负数,则两个数字不相等。
function isMinus(number){ return number !== (number >>> 0); }
正浮点数取整
function toInt(floatNumber){ return floatNumber >>> 0; }
正负浮点数取整
function toInt(floatNumber){ return floatNumber | 0; }
function toInt(floatNumber){ return ~~floatNumber; }
function toInt(floatNumber){ return floatNumber >> 0; }
十进制转换成二进制
function dec2bin(dec){ return (dec).toString(2); }
二进制转换成十进制
function bin2dec(bin){ return parseInt(`${bin}`, 2) }
参考
加载全部内容