位运算的自我检测题:
先来开胃菜帮助热身,如果检测题错误超过一半的话,那么说明你需要这篇文章。
var num1 = 1 & 0;console.log(num1);var num2 = 'string' & 1;console.log(num2);var num3 = true & 1;console.log(num3);var num4 = undefined | false;console.log(num4);var num5 = undefined | true;console.log(num5);var num6 = 23 & 5;console.log(num6);var num7 = 23 | 5;console.log(num7);var num8 = 8 << 'string';console.log(num8);var num9 = ({}) && 3;console.log(num9);var num10 = ({}) & 3;console.log(num10);var num11 = ({}) || 3;console.log(num11);var num12 = ({}) | 3;console.log(num12);复制代码至于附带解释的答案,就留到文章后面吧(有的解释需要配合前面的理论讲解更下饭哦~)
什么是位运算:
位运算符用于在最基本的层次上(即按照内存中表示数值的位来操作数值),ECMAScript中的所有数值都以IEEE-754 64位格式来存储,但位操作符并不直接操作64位的值。而是先将64位的值转换为32位的整数,再执行操作,最后再将结果转换为64位。
对于有符号的整数,32位中的后31位用于表示整数的值,第1位表示数值的符号:0表示正数,1表示负数。
正数正数以纯二进制格式存储,31位中的每1位都表示2的幂(还有1位是符号位)。第一位表示2,第二位表示2,第三位表示2,以此类推。没有用到的位以0表示(即忽略不计)。
负数负数同样以二进制码存储,但使用的格式是二进制补码。计算一个数值的二进制补码(即求一个负数的二进制码),需要经过下列3个步骤:①.求这个数值绝对值的二进制码(比如要求-18的二进制补码,先求18的二进制码)。②.求二进制反码,即将0替换为1,将1替换为0。③.得到的二进制反码+1.
//以求-18的二进制补码为例://先求18的二进制码:00000000 00000000 00000000 00010010//求18的二进制反码:11111111 11111111 11111111 11101101//得到的二进制反码+1:11111111 11111111 11111111 11101110(这就是-18的二进制反码)复制代码位运算符的底层处理过程:
根据ECMA规范,当使用位运算符时,底层会做以下处理:
非数值应用位操作符:会先使用Number()函数将该值转换为一个数值(自动完成),然后再应用位操作,得到的结果将是一个数值(number类型)。
数值应用位操作符:64位的数值将被转换为32位的数值,然后执行位操作,最后再将32位的结果转换为64位数值。(在JavaScript内部,数值都是以64位浮点数的形式储存)。这样表面看起来像是在操作32位数值,就跟在其它语言中以类似的方式执行二进制操作一样。但这个转换过程也导致了一个副作用:就是在对NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。
位运算的特点:
1.位运算直接对二进制位进行计算,位运算直接处理每一个比特位,是非常底层的运算。(优点:速度极快,缺点:很不直观,许多场合不能够使用)。
2.位运算只对整数起作用,如果一个运算数不是整数,会自动将其转为整数后再运行(可以利用位运算取整)。
位运算符都有哪些:
1.按位 与(AND):&
& 以 特定的方式 组合操作 二进制 数中对应的位, 如果对应的位都为1,那么结果就是1。如果任意一个位是0,则结果就是0。(速记:二一为一)
2.按位 或(OR):|
| 运算符跟 & 的区别在于如果对应的位中任一个操作数为1,那么结果就是1。(速记:有一则一)
3.按位 异或(XOR):^
^ 如果对应两个操作位 有且仅有1个1时结果为1,其它都是0。(速记:仅1个1为1)
4.按位 非(NOT):~
注1:在二进制码中,为了区分正负数,采用最高位是符号位的方法来区分,正数的符号位为0、负数的符号位为1.剩下的就是这个数的绝对值部分,可以采用原码、反码、补码3种形式来表示绝对值部分.注2:手动非~的规则 JavaScript内部采用补码形式表示负数(即需要将这个数减去1), 再取一次反, 表示为十进制后再加上负号, 才能得到这个负数对应的10进制值。
示例1:手动非~:
~ 运算符是对位求反,1变0,0变1,也就是求二进制的反码。
由于11111111 11111111 11111111 11111110中的第1位(符号位)是1,所以这个数是一个负数。
内部补码:11111111 11111111 11111111 11111101取 反 :00000000 00000000 00000000 00000010 => 即2表示为十进制后再加上负号:-2
所以 ~1 就是 -2
5.左移(Left shift):<<
<< 运算符使指定的二进制数所有位都左移指定次数,其移动规则为:丢弃高位,低位补0(即按照二进制形式把所有的数字向左移动对应的位数,高位移除(舍弃),低位的空位补0)
以1 << 3 为例:
1<<3 =>相当于 1x2 = 8。
结论:任何数的<<几位数,相当于:
6.有符号右移:>> (又称 “符号传播”)
>>该操作符会将指定操作数的二进制位向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧(这里是和无符号右移的最大区别)。由于新的最左侧的位总是和以前相同,而符号位并没有被改变。所以被称作“符号传播”。
以4 >> 2为例:
7.无符号右移:>>>
>>>该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充(这点是和有符号右移最大的区别)。因为符号位变成了0,所以结果总是非负的。
注:对于非负数,有符号右移和无符号右移总是返回相同的结果。
位运算符和逻辑运算符的区别(&&、&、||、|):
&&、&和||、|在我看来完全是不同的符号(事实也确实如此)。
运算结果不同:①.作为判断语句判断使用:
if(({}) && 3){ console.log("true")}else{ console.log("false");}//输出结果为trueif(({}) & 3){ console.log("true")}else{ console.log("false");}//输出结果为falseif(({}) || NaN){ console.log("true")}else{ console.log("false");}//输出结果为trueif(({}) | NaN){ console.log("true")}else{ console.log("false");}//输出结果为false复制代码②.作为赋值判断语句使用:
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.