你可能不知道的JavaScript位运算符详解
目录
- 概览
- 位操作符概览
- 位操作支持多少位?
- 负数的无符号右移
- -2 >>> 1为什么输出2147483647?
- 状态控制
- 权限控制
- 判断奇偶数
- 交换两个变量的值
- 判断整数是否相等
- 判断是否为负数
- 正浮点数取整
- 正负浮点数取整
- 十进制转换成二进制
- 二进制转换成十进制
- 参考
概览
本文详细剖析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) }
参考
- 聊聊JavaScript中的7种位运算符,看看在实战中如何妙用?
- 负数的二进制表示方法(正数:原码、负数:补码)
到此这篇关于JavaScript位运算符的文章就介绍到这了,更多相关JS位运算符内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!