从此无心爱良夜,任他明月下西楼

js位运算的特殊之处,消除所有小数

在学习的时候突然发现了dalao代码中的神奇操作,  num>>0 他这样做是为了舍弃小数。事实也确实做到了这样的功能。但是我就很不理解,为什么位运算,有符号右移0位会舍弃掉全部小数,于是有了以下的了解。

一、js的位运算为什么特殊

对于位运算最浅显的认识就是按位运算,那么肯定要想一想js中是怎么按位存储Number类型的。

同时在 js 中的 Number 类型是不区分 int、long、float、double 类型的,那么Number的存储方式一定是能满足浮点型的。所以为了不丢失精度, js 中的 Number 类型实际上一个基于 IEEE 754 标准的双精度64位浮点数。

由于浮点型不能进行位运算(没意义,且有安全隐患),所以js必须在Number不允许位运算和Number位运算时完全舍弃小数部分做选择。

然后js就选择了舍弃Number的小数部分。

在js中对Number进行任何位运算时都会导致小数部分被舍弃。所以 >> 0、 << 0 、~~num都可以做到舍弃小数。(其他操作可能会改变整数部分,不一一列举)

二、除此之外的特殊性

上面提到的舍弃小数,也算是实用的特性了,但是还又有一些不好评价甚至可能出错的特殊性。

1、js 中的无符号右移

对比java,js的无符号右移就有一些神奇的地方了。 java 中在并没有真正发生移位的情况下,符号位会不会被替换成0。但是 js 中是会发生替换的。

当操作数是正数的时候,不管有没有真的移位并没有区别,因为正数的符号位是 0。
当操作数是负数时,移动位数大于0,也体现不出区别:

// java
5 >>> 0  // 5
5 >>> 1  // 2
-1 >>> 1 // 2147483647

// js
5 >>> 0  // 5
5 >>> 1  // 2
-1 >>> 1 // 2147483647

但是当操作数是负数,无符号右移 0 位时,区别就大了:

// java
-1 >>> 0 // -1

// js
-1 >>> 0 // 4294967295

这是因为按照-1的补码 11111111111111111111111111111111 进行位移时,js中首位设置为0了,于是变成了一个超大的正整数 01111111111111111111111111111111 

 2、js 中非数值类型如何进行位运算的呢

当 js 需要进行位运算的时候,对于非数值类型,会首先将操作数转成一个整型(就是0)然后在进行运算。这就解释了为什么 js 中可以允许非数值类型参与运算,其实这是个伪命题,因为实质上是对非数值操作数的整型表达式进行的位运算。
所以对一个非数值变量做取反操作,得到的一定是 -1,因为实际上等于对 0 做取反操作。

posted @ 2022-09-20 15:11  明月下  阅读(568)  评论(0编辑  收藏  举报

页脚