位运算符与逻辑运算符
位运算符|,& 不是逻辑运算符||,&& !!! 铭记这一点,必须区分开
- 位运算符|
运算规则是对于每一位,只要有一位的数字是1,那么该位的数字就是1
- 位运算符&
运算规则是对于每一位,必须该位的都是1,该位的数字才是1
console.log(3|1);// 3,1分别转换为位是 11,01 ,11 =>3
console.log(9|2);// 9,2转换为位是 1001,0010,=>1011=> (8+2+1)=>11
console.log(3&1);// 3,1分别转换为位是 11,01, 01 =>1
console.log(9&2);// 9,2转换为位是 1001,0010,=>0000=> 0
当对非数字数据类型使用位运算符的时候,先把数据转换为数字类型(NaN(虽然NaN也是Number数据类型)/null/undefined在位运算中相当于0)
console.log(false|9);//9
console.log(null&9);//0
console.log(true|9);//0001,1001 =>1001 => 9
console.log(true&9);//0001,1001 =>0001 => 1
console.log(NaN|9);//9
console.log(NaN&9);//0
- 逻辑运算符||
如果第一个数是true,那么就不需要判断后面的数据,直接输出第一个数,否则继续后面的数,直到为true,或者都不为true,那就返回最后一个数
- 逻辑运算符&&
如果第一个数是false,那么就直接返回false,不需要判断后面的数据。直到找到false,或者全部都是true,那就返回最后一个值
console.log(false||9);//9
console.log(NaN||false||1);//1
console.log(true||9);//true,在||或逻辑运算中,返回第一个true
console.log(true&&9);//9,在&&与逻辑运算中,返回最后一个true
console.log(1&&9&&true);//true
- 在逻辑运算中,
NaN/null/undefined相当于false
- 参考
按位运算符
^按位异或(都为1的话就是0,都是0也还是0,只有01,10才是1)
console.log(1^6);//0000001 , 0000110 => 0000111 = 4+2+1=7
console.log(2^18);//0000010,0010010 => 0010001 =>16 (因为两个1得出0)
~按位非(整数的相反数减一 (~num=-num-1))
- 注意
对一个整数进行按位求反,其实就是对整数的相反数减一 (~num=-num-1)
对一个数进行两次按位求反的结果就是这个数本身,对一个浮点数进行按位求反那么就会先去除整数部分,然后再对整数进行运算
对于非数字类型,会先转换为数字再进行按位非操作
console.log(~2);// -2-1=-3
console.log(~~3);// -(-3-1)-1=3+1-1=3
console.log(~3);// -3-1=-4
console.log(~-3);// -(-3)-1=3-1=2
console.log(~~-3);// -(-(-3)-1)-1=-2-1=-3
console.log(~false);// -0-1=-1
console.log(~null);// -0-1=-1
- 按位与&,按位或|
左移运算符<<(所有数字向左移动,高位移出,低位补零)(没有无符号左移!)
console.log(1<<4);// 0000001 => 0010000 => 16
console.log(-1<<4);//-16
console.log((-1)<<4);//-16
//没有无符号左移
// console.log(1<<<4);// 0000001 => 0010000 => 16
console.log(23<<3);// 00010111 => 10111000 => 8+16+32 =>56+128=>184
console.log(-23<<3);//-184
在左移运算符中,即使数字是负数,依旧操作,只是不改变正负就好了
右移运算符>> (所有数字向右移动,低位移出,高位的话,正数补零,负数补1!!!)
console.log(33>>3);// 00100001 => 00000100 => 4
// 负数在内存中是以补码形式存在的,所以负数带符号右移需要现在转换为补码
console.log(-33>>3);// 00100001(原码) => 11011111(原码+1=>补码) => 1111011(右移三位) => 0000101(按位取反+1)=> 5,但是本来是负数,所以保留符号是-5
console.log(-100>>4);// 01100100 => 10011100(按位取反+1 =>补码)= > 11111001=> 00000111(按位取反+1) => 7=>-7
console.log(-33>>>3);//(无符号右移,此时就不仅仅看8位就可以了,还要知道符号是32位的)
// 无符号右移 >>> 其实也是差不多,但是右移之后是给高位补0而不是1了
// 00000000 00000000 00000000 00100001=>1111111 1111111 1111111 11011111(原码+1=>补码)=>0001111 1111111 1111111 1111011(右移三位)
无符号右移>>> 这个不太一样,虽然也是对负数按位取反,但是之后是补0 (在按位取反之后,把负数当做整数处理了)
注意,整数的无符号右移依旧是右移的数值
// 记住!其实都是32位的,但是为了方便只写出8位
console.log(2&6);//00000010 00000110 =>00000010 =>2
console.log(2|6);//00000010 00000110 =>00000110 =>6
console.log(2^6);//00000010 00000110 =>00000100 =>4
console.log(~2);//num=-num-1; -2-1=-3
console.log(~-2);// -(-2)-1=1
console.log(34>>4);//00100010 =>00000010 =>2 (正数补0)
console.log(-34>>4);//先按位取反+1,转为内存中的负数形式 11011110
// 然后再右移4位 (负数的话高位的就补1) 11111111 11111111 11111111 11111101
//然后再按位取反+1 00000011 =>3 => 保留符号,所以是-3
console.log(-34>>>4);//无符号右移,先按位取反+1 11011110
//然后再右移4位(但是!!!此时是高位补0) 00001111 11111111 11111111 11111101 这就是结果了
console.log(3<<3);//左移3位, 00000011 => 00011000 => 24