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

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

相关推荐
Myli_ing29 分钟前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维1 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
I_Am_Me_1 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ1 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z1 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
前端百草阁2 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜2 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4042 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish2 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue