计算机系统中,数值一律采用补码来表示和存储(寄存器)。 javascript 中所有数字均用浮点数值表示,采用 IEEE 754 标准定义的 64 位浮点格式表示数字。
javascript 中实际的操作(数组索引以及位操作符)都是基于 32 位整数(有符号)。操作完成之后,再按照 64 位浮点数存储。
~~212121212121123=1367306275 原数:212121212121123 转二进制
toString(2)
:110000001110110001010001011111110111000000100011 JS 32位(舍掉超出位数):01010001011111110111000000100011~~
执行之后:01010001011111110111000000100011 转十进制parseInt('', 2)
:1367306275
javascript 中的整型在内存中都是一个 64 位双精度浮点型,但是 js 进行位运算时,会将操作数转成带符号位的 32 位比特序列 01
(补码)。运算结束后,再按照 64 位浮点格式存储。这样导致的结果:精度丢失(直接截断)!
注意: 所有操作都是基于计算机存储的补码进行操作的。
正数(3) | 负数(-3) | |
---|---|---|
原码 | 0000 0000 0000 0000 0000 0000 0000 0011 | 1000 0000 0000 0000 0000 0000 0000 0011 |
反码 | 0000 0000 0000 0000 0000 0000 0000 0011 | 1111 1111 1111 1111 1111 1111 1111 1100 |
补码 | 0000 0000 0000 0000 0000 0000 0000 0011 | 1111 1111 1111 1111 1111 1111 1111 1101 |
运算符 | 3 [opt] -3 |
---|---|
&(AND) | 0000 0000 0000 0000 0000 0000 0000 0001(1) |
|(OR) | 1111 1111 1111 1111 1111 1111 1111 1111 (-1) |
^(XOR) | 1111 1111 1111 1111 1111 1111 1111 1110(-2) |
运算符 | 说明 |
---|---|
左移 a << b | 将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零 |
右移 a >> b | 将第一个操作数右移指定的位数。右移的多余位被丢弃。符号位不变。 |
无符号右移 a >>> b | 将第一个操作数右移指定的位数。右移的多余位被丢弃。左边将会补零(结果始终为非负) |
注意: 移位运算符在 CPU 中的运算器进行操作的,采用补码。
a = -5 // 11111111111111111111111111111011
a >> 2 // 11111111111111111111111111111110 => 10000000000000000000000000000010
a >>> 2 // 00111111111111111111111111111110
javascript中浮点数也能参与运算
javascript 中实际的操作(数组索引以及位操作符)都是基于 32 位整数(补码)。操作完成之后,再按照 64 位浮点数存储。
小数部分,全部舍弃
~~1.1 // 1
~~-2.2 // -2
非数值类型
首先将操作数转成一个整型(就是0),然后进行运算
null >>> 0 // 0
function right () {}
right >>> 0 // 0
javascript 中无符号右移 >>>
特别之处
-1 >>> 0 // 4294967295
原码:10000000 00000000 00000000 00000001
补码:11111111 11111111 11111111 11111111
右移:11111111 11111111 11111111 11111111 // 无符号
注意:与其它按位运算符不同,无符号右移返回无符号 32 位整数。
清零
任何数与0做与运算结果都是0
123123 & 0 // 0
-12312 & 0 // 0
奇数偶数判断
二进制的末尾是0则是偶数,为1则是奇数
(x & 1) === 0 // 偶数为true,奇数为false
交换两数值
x ^= y
y ^= x
x ^= y
位移枚举(与传统枚举,可支持多选)
举例,对于数据权限,通常包括增、删、改、查;某角色对某一数据权限,往往是一对多的过程(如只具备:增、查权限)
const Permission = {
None: 0, // 0000 0
Get: 1 << 0, // 0001 1
Post: 1 << 1, // 0010 2
Put: 1 << 2, // 0100 4
Delete: 1 << 3 // 1000 8
}
获取是否具有权限
function resolvePermission (payload) {
return {
Get: !!(payload & Permission.Get),
Post: !!(payload & Permission.Post),
Put: !!(payload & Permission.Put),
Delete: !!(payload & Permission.Delete)
}
}
resolvePermission(3) // {Get: true, Post: true, Put: false, Delete: false}
resolvePermission(15) // {Get: true, Post: true, Put: true, Delete: true}
延伸1:查找给定数字num
的特定位置i
function getBit (num, i) {
return ((num & (1 << i)) !== 0)
}
getBit(5, 0) // true
getBit(5, 1) // false
getBit(5, 2) // true
延伸2:给定数字num
的特定位置i
设置位
function setBit (num, i) {
return num | (1 << i)
}
延伸3:清除给定数字num
的特定位置i
处的位
function clearBit (num, i) {
let mask = ~(1 << i)
return num & mask
}