^ | & ~ >> _ << ** ?? 这些 JS 运算符,试试你会几个

^ | & ~  >> _ << ** ?? 这些 JS 运算符,试试你会几个

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

相信很多小伙伴第一次看到 Javascript 这些运算符号时,一脸懵逼。我不一样,初看懵逼我闪了,所以看到这些运算符,两脸懵逼。为了避免看不懂同事写的牛逼代码,整理此文。

位运算符

| & ~ ~~ ^ >> << 这些都是二进制操作符,直接在数值的二进制形式上进行操作。

按位或 |

直接对数字的二进制形式进行运算,每位有一个为1则是1。

var i = 8 | 1
console.log(i);	// 9
复制代码
8 = 0000 0000 0000 0000 0000 0000 0000 1000 
1 = 0000 0000 0000 0000 0000 0000 0000 0001 
-------------------------------------------- 
OR = 0000 0000 0000 0000 0000 0000 0000 1001
复制代码

二进制 1001 转为10进制为9。

按位与 &

直接对数字的二进制形式进行运算,每位都为1才是1,否则为0。

var i = 10 & 3
console.log(i);	// 2
复制代码
10 = 0000 0000 0000 0000 0000 0000 0000 1010 
3  = 0000 0000 0000 0000 0000 0000 0000 0011 
-------------------------------------------- 
AND = 0000 0000 0000 0000 0000 0000 0000 0010
复制代码

二进制 0010 转为10进制为2。

按位异或 ^

直接对数字的二进制形式进行运算,每位相等则为0,不相等为1。

var i = 10 ^ 3
console.log(i);	// 9
复制代码
10 = 0000 0000 0000 0000 0000 0000 0000 1010 
3  = 0000 0000 0000 0000 0000 0000 0000 0011 
-------------------------------------------- 
XOR = 0000 0000 0000 0000 0000 0000 0000 1001
复制代码

二进制 1001 转为10进制为9。

按位非 ~

直接对数字的二进制形式进行运算,对任一数值 x 进行按位取反操作。

var i = ~5
console.log(i);	// -6
复制代码

其结果为 -(x + 1),计算原理如下:


5      = 0000 0000 0000 0000 0000 0000 0000 0101 
~      = 1111 1111 1111 1111 1111 1111 1111 1010
-------------------------------------------- 
32位开头第一个是1,所以这是一个负数。
将二进制转换成负数,需要先反码之后,再+1,转为10进制之后,加上负数。

反码    = 0000 0000 0000 0000 0000 0000 0000 0101
反码+1  = 0000 0000 0000 0000 0000 0000 0000 0110 (转换成十进制为6)

转换成十进制为6,加上符号变成负数 -6
复制代码

~x 再次取反就是 ~~x, 就为 -(-(x+1) + 1)。 对于浮点数,~~value可以代替 parseInt(value)

console.log(~~10.5) // 10
console.log(~~-10.5) // -10
复制代码

而且前者效率更高些。虽然 ~~ 他的缺点是难懂,但优点是可以用来装*哇。

var count = 5000000;
var h = 2.101;

console.time('parseInt');
for (var i = count; i > 0; i--) {
    parseInt(h);
}
console.timeEnd('parseInt'); // 55.91796875 ms

console.time('~~');
for (var i = count; i>0; i--) {
    ~~h;
}
console.timeEnd('~~'); // 21.987060546875 ms
复制代码

右移 >>

右移操作符将第一个操作数向右移动指定位数,右边超出的位数将会被清除,左边将会补零。

var i = 10 >> 3
console.log(i);	// 1

var j = 4 >> 3
console.log(j);	// 0
复制代码
10  = 0000 0000 0000 0000 0000 0000 0000 1010 
-------------------------------------------- 
>>3 = 0000 0000 0000 0000 0000 0000 0000 0001

4   = 0000 0000 0000 0000 0000 0000 0000 0100 
-------------------------------------------- 
>>2 = 0000 0000 0000 0000 0000 0000 0000 0000

复制代码

二进制 0001 转为10进制为1,0000 为0。

左移 <<

左移操作符将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零。

var i = 1 << 3
console.log(i);	// 8
复制代码
1    = 0000 0000 0000 0000 0000 0000 0000 0001 
-------------------------------------------- 
<< 3 = 0000 0000 0000 0000 0000 0000 0000 1000 
复制代码

二进制 1000 转为10进制为8。

其他非二进制运算符

幂运算符 **

幂运算符 (**) 返回将第一个操作数和第二个操作数求幂的结果。它等同于 Math.pow,但它也接受 BigInts 作为操作数。

console.log(3 ** 4);
console.log(Math.pow(3, 4));
// expected output: 81

console.log(10 ** -2);
console.log(Math.pow(10, -2));
// expected output: 0.01
复制代码

求幂运算符是右结合的:a ** b ** c 等于 a ** (b ** c)。

console.log(3 ** 2 ** 2);
console.log(3 ** (2 ** 2));
// expected output: 81
复制代码

但注意哦,如果底数为负数的话,请用以下语法。

(-4) ** 2
// expected output: 16
复制代码

或者如果你期待对求幂之后的数取反,应该如下:

- (4 ** 2)
// expected output: -16
复制代码

使用模棱两可的语法,会报错。

- 4 ** 2
// Uncaught SyntaxError: Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence
复制代码

幂赋值运算符 **=

幂赋值运算符 (**=) 将变量赋值为其初识值和等号右边的值求幂后的值。

let a = 3;

console.log(a **= 2);
// expected output: 9

console.log(a **= 0);
// expected output: 1

console.log(a **= 'hello');
// expected output: NaN
复制代码

空值合并操作符 ??

空值合并操作符?? )是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。

var a = null;
var b = undefined;

var aa = a ?? 'xxx'
console.log(aa) // 'xxx'

var bb = b ?? 'yyy'
console.log(bb) // 'yyy'
复制代码

初看和 || 很相像,请看当左值为 0 或 '' 时的区别

var a = 0;
var b = '';

console.log(a ?? 'xxx') // 0
console.log(a || 'xxx') // xxx

console.log(b ?? 'yyy') // ''
console.log(b || 'yyy') // yyy
复制代码

?? 只在左侧的操作数为 null 或者 undefined 时,返回右值,谨记。

数字分隔符 _

碰到一个长数字数不过来,不知道它有几位?es 新标准 数字分隔符 _ 就是用来解决这个问题的。 准确来说,它并不是运算符。为了凑数,而放进来的。它的提议见 github.com/tc39/propos…

let budget = 1_000_000_000_000;

// 它是一个数字,不信可以确认
console.log(budget === 10 ** 12); // true

let budget2 = 1_000

console.log(budget2 === 10 ** 3); // true
复制代码

有没有觉得很清爽。

参考致谢

感谢阅读,写得头发都秃了,你懂的。

pigu.gif

分类:
前端