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

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

相关推荐
陈随易1 小时前
在 VSCode 里,把项目一键部署到服务器
前端·后端·程序员
Highcharts.js1 小时前
教程:基于 React + Highcharts 构建一个单页应用程序、按需数据拉取与图表渲染
开发语言·前端·数据结构·react.js·前端框架·highcharts·页面应用
To_OC1 小时前
我被 useState 坑了两次之后,终于把它的脾气摸透了
前端·javascript·react.js
鱼樱前端2 小时前
我用 Claude Code 后,编码效率翻 3 倍。但更值钱的是别的。
前端·后端·ai编程
_lucas2 小时前
给知识库网站接入AI问答
前端·ai编程·全栈
前端糕手3 小时前
前端面试题大全:JavaScript + Vue3 + React + TypeScript + 工程化 + 性能优化
前端
我不叫武4 小时前
一个用 Rust 写的离线编码查询桌面工具
前端
Web4Browser5 小时前
指纹浏览器 API 自动化怎么接:启动 Profile、获取 CDP 端点并连接自动化框架
前端·网络·typescript·自动化
Patrick_Wilson5 小时前
从 React 到 Flutter:写给前端的一张跨端知识地图
前端·flutter·react.js
颜酱5 小时前
06 | 把 meta_config 同步进 MySQL(生成阶段)
前端·人工智能·后端