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

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

相关推荐
正小安27 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript