位运算与逻辑运算的妙用

这是我参与更文挑战的第 26 天,活动详情查看:更文挑战

JavaScript 语言存在以下位运算:

运算符 Usage Description
按位与(& a & b 在a,b的位表示中,每一个对应的位都为1则返回1, 否则返回0.
按位或(| a | b 在a,b的位表示中,每一个对应的位,只要有一个为1则返回1, 否则返回0.
按位异或(^ a ^ b 在a,b的位表示中,每一个对应的位,两个不相同则返回1,相同则返回0.
按位非(~ ~ a 反转被操作数的位。
左移(<< a << b 将a的二进制串向左移动b位,右边移入0.
右移(>> a >> b 把a的二进制表示向右移动b位,丢弃被移出的所有位.(注:算术右移左边空出的位是根据最高位是0和1来进行填充的)
无符号右移,左边空出位用0填充(>>> a >>> b 把a的二进制表示向右移动b位,丢弃被移出的所有位,并把左边空出的位都填充为0

还有以下逻辑运算:

运算符 范例 描述
逻辑与 (&&) expr1 && expr2 如果expr1能被转换为false,那么返回expr1;否则,返回expr2
逻辑或 (||) expr1 || expr2 如果expr1能被转换为true,那么返回expr1;否则,返回expr2
逻辑非 (!) !expr 1、将 expr 转化为布尔类型:true/false,2、返回相反的布尔值

逻辑运算我们平时用的会比较多,主要用于条件判断,而位运算符就用得比较少。由于JavaScript动态类型的特性,导致在很多情况下逻辑运算跟位运算会起到一些特殊的妙用。

逻辑运算

JavaScript的逻辑运算不仅可以用于布尔值,也可以用于其它类型,返回值也可以是任意类型。

从上表的逻辑运算描述中可以发现,逻辑与和逻辑或运算,返回的并不是布尔值,而是操作数(可能是表达式)本身,而逻辑非运算则是返回一个布尔值。

我们利用逻辑运算符的相关特性,挖掘一些传统方式以外的用法。

1、短路求值

逻辑与和逻辑或运算都有一个「短路求值」特性,从左到右对参数进行处理,找到一个满足条件的参数就直接返回,如果前面的几个参数都不满足,就直接返回最后一个参数。

利用这个特性,可以做一些特别的操作如下:

// 返回第一个真值或假值
let result = null || 0 || 1 || undefined; // 1
let result = 1 && 2 && null && 3; // null

// 也可以是表达式,但建议还是用`if`,提高代码可读性
num > 0 && console.log('num 大于 0');
num > 0 || console.log('num 小于 0');

// 等价于
if (num > 0) {
    console.log('num 大于 0');
}
if (num < 0) {
    console.log('num 小于 0');
}
复制代码

2、布尔值转换

非运算常常被用于将操作数转换为布尔值,效果等同于Boolean函数,如下所示。

!!"non-empty string" // true
!!null // false
复制代码

注意运算优先级, ! > && > ||

位运算

相比逻辑运算符,位运算符有更多的妙用。

1、位运算取整

JavaScript 内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。

借助这个特性,我们可以很方便的进行取整的操作:

~~ -3.14 // 3
3.14 >> 0)  // 3
3.14 << 0)  // 3
3.14 | 0   // 3
3.14 >>> 0 // 3, 不能对负数进行该操作
3.14 ^ 0 // 3
复制代码

需要注意的是,这种取整方法不适用超过32位整数最大值2147483647的数。

使用二进制否运算取整,是所有取整方法中最快的一种。

对字符串进行二进制运算,JavaScript 引擎会先调用Number函数,将字符串转为数值。Number的转换规则可见看LvLin写的这篇JavaScript 类型转换

2、2 次方的乘除实现

利用左移(右移)运算,可以迅速实现乘(除)以一个2的指定次方,如下所示:

4 << 1  // 8
-4 << 1 // -8

4 >> 1 // 2
-4 >> 1 // -2
复制代码

3、两数互换

借助异或运算的特性,实现两数互换。

var a = 10;
var b = 99;

a ^= b, b ^= a, a ^= b;
复制代码

这是互换两个变量的值的最快方法。

4、颜色的 RGB 值与 HEX 值转换

综合使用多种位运算实现颜色的 RGB 值与 HEX 值转换。

// HEX 值转 RGB 值
function hexToRGB(hex) {
    hex = hex.replace('#', '0x');
    
    let r = hex >> 16;
    let g = hex >> 8 & 0xff;
    let b = hex & 0xff;
    return `rgb(${r}, ${g}, ${b})`;
}

// RGB 值转 HEX 值
function RGBToHex(rgb) {
    let rgbArr = rgb.split(/[^\d]+/)
    let color = (rgbArr[1] << 16) | (rgbArr[2] << 8) | rgbArr[3]
    return '#'+ color.toString(16)
}
复制代码

5、奇数偶数判断

通过按位与运算判断一个数的奇偶性,判断二进制最低一位是 0 还是 1。

2 & 1  // 0 , 偶数
5 & 1  // 1 , 奇数
复制代码

其它一些 JS 技巧(持续补充)

undefined == null // 空值的排除
NaN !== NaN  // NaN 的判断
复制代码

6、除法异常处理

利用或运算,对除法运算的结果做取整以及异常处理。

let a = (num / 100) | 0;
(101 / 100) | 0 // 1
('abc' / 100) | 0 // 0
(Infinity / 1) | 0 // 0
复制代码

相关资料

表达式与运算符

逻辑运算符

运算符

位运算符在JS中的妙用

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享