在学习的时候突然发现了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 做取反操作。