按位非(~)本质是逐位取反,等价于-(x+1);~~x可向零取整(同Math.trunc),常用于索引判断和快速截断,但有32位溢出限制,日常推荐语义明确的标准方法。

JavaScript 中的按位非运算符 ~ 本身只做一件事:对操作数的**每一位取反**(0 变 1,1 变 0),它不是专门用来“取整”的,但利用其底层行为(补码表示 + 整数截断)可以**快速实现向下取整(floor)**,尤其对非负数效果直观。注意:这不是它的设计目的,而是二进制特性带来的副作用。
按位非的本质:逐位取反 + 补码偏移
~x 等价于 -(x + 1)(对所有整数成立)。这是因为 JavaScript 使用 32 位有符号补码表示整数:
- 先对 x 的 32 位二进制表示逐位取反;
- 再加 1 得到补码负数,而按位非跳过了“加 1”,所以结果正好是 -(x + 1)。
例如:~5 → 5 的 32 位二进制是 ...00000101,取反得 ...11111010,解释为补码即 -6;
验证:-(5 + 1) === -6 ✅
用 ~~x 快速转为 32 位整数(类似 Math.trunc)
连续两次按位非:~~x,相当于 ~(~x) = x,但它会先将操作数强制转为 32 位有符号整数,再转回 JS 数字,从而**丢弃小数部分**(向零取整):
- ~~3.7 → 先 ~3.7 是 ~3(自动截断)得 -4,再 ~-4 得 3;
- ~~-2.8 → ~-2.8 是 ~-2 得 1,再 ~1 得 -2;
这和 Math.trunc(x) 行为一致(ES6 引入,更语义化)。
常见用途与注意事项
-
数组索引判断:检查某值是否在数组中,常写
if (~arr.indexOf(x))。因为indexOf找不到返回-1,而~-1 === 0(falsy),其余索引如0,1,2...经~后变为-1,-2,-3...(truthy),避免显式写!== -1。 -
快速取整仅限安全整数范围:
~~x依赖 32 位整数转换,对绝对值 > 2³¹−1(即 > 2147483647)的数会溢出失真,此时应改用Math.trunc(x)或Math.floor(x)。 -
不适用于浮点精度要求高的场景:按位运算会丢失小数,且对
NaN、Infinity返回0或-1,语义模糊,可读性不如标准方法。
替代方案推荐(更清晰可靠)
- 向下取整(floor)→ 用
Math.floor(x) - 向零取整(trunc)→ 用
Math.trunc(x)(推荐)或parseInt(x, 10) - 转整数并处理溢出 →
Math.round(x)或x | 0(同~~x,但单次位或更轻量)
按位非是底层技巧,理解原理有助于阅读老代码或做性能敏感的底层操作,但日常开发优先选语义明确的标准方法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











