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];

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

相关推荐
安全系统学习3 分钟前
网络安全逆向分析之rust逆向技巧
前端·算法·安全·web安全·网络安全·中间件
花开月满西楼4 分钟前
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
android·前端·android studio
KENYCHEN奉孝6 分钟前
基于 actix-web 框架的简单 demo
前端·rust
wordbaby20 分钟前
🎯 satisfies 关键字详解(TypeScript)
前端·typescript
超级土豆粉30 分钟前
CSS 性能优化
前端·css·性能优化
Mintopia33 分钟前
光影魔术师的秘密:用 JavaScript 打造软阴影的奇幻世界
前端·javascript·计算机图形学
Mintopia1 小时前
Three.js 粒子系统:让代码化身奇幻造梦师
前端·javascript·three.js
mpr0xy1 小时前
React Router 中 navigate 后浏览器返回按钮不起作用的问题记录
javascript·react.js·浏览器·路由
itwlz1 小时前
vite配置@别名,以及如何让IDE智能提示路经
开发语言·前端·javascript
lichenyang4531 小时前
添加按钮跳转页面并且根据网站的用户状态判断是否显示按钮
开发语言·前端·javascript