JavaScript中,按位非(~)的介绍以及妙用

JavaScript中,按位非(~)的介绍以及妙用

最近改老代码经常看到这个符号,对于一个新人,很少见这个符号,初看还是有点阅读阻碍的。所以就查了一下。

按位非(~)

按位非运算符(~)将操作数的位反转。如同其他位运算符一样,它将操作数转化为 32 位的有符号整型。 简单理解就是 ~a等价于-(a + 1)

示例:

javascript 复制代码
let arr = [1,2,3,4];
let item = 5;
if (~arr.indexOf(item)) {
....
}

这段代码实际上是在利用按位非运算符的一个小技巧。

indexOf 方法会返回查找元素的索引,如果找到了元素,其返回值是 0 或正整数(表示元素的位置索引)。如果没有找到,它会返回 -1

按位非运算符 ~ 的一个特性是,当应用于 -1 时,它会返回 0(因为 -1 在二进制中是所有位都为 1,取反后所有位变为 0),而当应用于任何其他的非负整数时,结果总是一个负值。

这意味着你可以这样用它来检查 indexOf 的结果:

javascript 复制代码
if (~arr.indexOf(item)) {
    // 如果 item 存在于数组中,indexOf 返回非 -1 的索引,取反后为负值,
    // 由于负值在 if 条件判断中为真,这个代码块会执行。
} else {
    // 如果 item 不存在于数组中,indexOf 返回 -1,取反后为 0,
    // 0 在 if 条件判断中为假,这个代码块不会执行。
}

这是一种在 JavaScript 中比较老练的方式来检查一个元素是否存在于数组中。然而,这种方法的可读性并不是很好,特别是对于不熟悉这个技巧的开发者。更现代、更直观的方法是使用 includes 方法,它返回一个布尔值,直接告诉你元素是否存在于数组中:

javascript 复制代码
if (arr.includes(item)) {
    // 如果 item 存在于数组中,执行这个代码块
} else {
    // 如果 item 不存在于数组中,执行这个代码块
}

这种方式更容易读懂,也是推荐的做法。说到底这种方式就不太适合阅读,然后有天看到了篇更加逆天的文章。

双按位非 (~~)

双重位运算符 NOT (~~) 在 JavaScript 中的作用是将一个数值取反,然后再次取反。具体来说,它会将操作数转换为32位整数,然后将每个位取反,即将0变为1,将1变为0。这个操作等同于 -(foo + 1)。因此,双重位运算符 NOT (~~foo) 的结果将是 -(-(foo + 1) + 1)。

然而,这个操作仅对整数有效。对于所有可能的操作数,~~ 的实际等效表达式可能是这样的:

javascript 复制代码
typeof foo === 'number' && !isNaN(foo) && foo !== Infinity
    ? foo > 0 ? Math.floor(foo) : Math.ceil(foo) : 0;

这意味着,如果操作数是数字且不是 NaN 或 Infinity,那么 ~~ 的效果将向零取整(负数向上取整,正数向下取整)。如果操作数不是数字,那么内部 ToInt32 函数将其转换为零。

以下是一些双重位运算符 NOT (~~) 的示例:

javascript 复制代码
~~null;      // => 0
~~undefined; // => 0
~~0;         // => 0
~~{};        // => 0
~~[];        // => 0
~~(1/0);     // => 0
~~false;     // => 0
~~true;      // => 1
~~1.2543;    // => 1
~~4.9;       // => 4
~~(-2.999);  // => -2

这种方法对于规范化预期为整数的参数也很有用。例如,MDC 建议为不支持的浏览器提供 Array.prototype.indexOf 时可以使用这种方法:

javascript 复制代码
/*Array.prototype.indexOf = function...*/
var from = Number(arguments[1]) || 0;  
from = (from < 0)  
     ? Math.ceil(from)  
     : Math.floor(from);

使用双重位运算符 NOT (~~) 后:

javascript 复制代码
/*Array.prototype.indexOf = function...*/
var from = ~~arguments[1];

看完之后,真是震惊。所以,多用用这种不常用的方式,是不是也算防御式编程

相关推荐
careybobo6 分钟前
海康摄像头通过Web插件进行预览播放和控制
前端
TDengine (老段)31 分钟前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
杉之2 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
喝拿铁写前端2 小时前
字段聚类,到底有什么用?——从系统混乱到结构认知的第一步
前端
再学一点就睡2 小时前
大文件上传之切片上传以及开发全流程之前端篇
前端·javascript
木木黄木木3 小时前
html5炫酷图片悬停效果实现详解
前端·html·html5
请来次降维打击!!!3 小时前
优选算法系列(5.位运算)
java·前端·c++·算法
難釋懷4 小时前
JavaScript基础-移动端常见特效
开发语言·前端·javascript
还是鼠鼠4 小时前
Node.js全局生效的中间件
javascript·vscode·中间件·node.js·json·express
自动花钱机4 小时前
WebUI问题总结
前端·javascript·bootstrap·css3·html5