JavaScript中 |、& 、!!、~操作符和任意进制转换

1,045 阅读6分钟

前言

在《JavaScript高级程序设计 第三版》中,在 逻辑操作符 与 位操作符 章节感觉被没有讲解清楚。

位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值。在JS中只能当做 数值 进行位运算

参考文档:按位操作符

常见操作符

1.按位与(AND)(位操作符)

按位与操作符由一个和号字符(&)表示,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,然后根据规则,对相同的位置上的两个数执行AND操作。

简而言之,按位与操作符只在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0。

var result = 25 & 3
console.log(result) // 1

25和3转化为32位的二进制码时,对应位上只有一位同时是1,而其它位的结果都是0,因此最终结果等于1.

2.按位或(OR)(位操作符)

按位或操作符由一个竖线符号(|)表示,同样也有两个操作数。 简而言之,按位或操作在有一个位是1的情况下就返回1,而只有在两个位都是0的情况下返回0。 如果在前面按位与的例子中对25和3执行按位或操作。如下:

var result = 25 | 3
console.log(result) // 27

这两个数值都包含4个1,因此可以把每个1直接放到结果中。二进制码 11011 等于十进制27。

JS中位运算符返回的是数值。JS中的位操作符只有1个功能:进行位运算

var number = 2
var logic = number < 5 | number > 0
console.log(number < 5) // true
console.log(logic) // 1 返回数值
var logic = true | true
console.log(logic) // 1 可以看出 位操作符 只有1个功能:进行位运算。 

测试1

var str1 = '9'
var str2 = '5'
console.log(str1 & str2) // 1
console.log(typeof (str1 & str2)) // 结果为 number 类型

测试2

var number1 = 9
var number2 = 5
console.log(number1 & number2) // 1

测试3

var obj1 = {
    valueOf: function() {
        return 9
    }
}
var obj2 = {
    valueOf: function() {
        return 5
    }
}
console.log(obj1 & obj2) // 1

9的二进制:1001 5的二进制:0101 &操作结果:0001 = 1

我们可以发现,string类型、number类型、object类型操作结果相等,都会进行相应的数值转换。如果操作数不是数值类型,就会根据一定规则先把它转换成数值,若不能转化成数值则为NaN。

console.log(NaN & NaN) // 0
console.log('string' & 'string') // 字符串转化为NaN,结果为0
console.log(10 & NaN) // 10 & 0, 结果为0

console.log(Infinity & -Infinity) // 0

3.强制转换类型(!!)

不论它的后面接的是什么数值,它的结果会被强制转换成bool类型

!!1 = true

!!0 = false

!!null = false

!!'' = false

!!'ccc' = true

!!{} = true

4. 按位非(~),按位取反

  • 1.按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。
let num1 = 3
var num2 = ~(num1) // -4 类似:(-1) - 3 = -4

let num3 = -3
let num4 = ~(num3) // 2 类似:(-1) - (-3) = 2

~(0) // -1 类似:-1 - (0) = -1

let num5 = 25;//25 等于 00000000000000000000000000011001

let num6 = ~num5;//转换为 11111111111111111111111111100110

alert(num6);//输出 "-26"

相当于 -1减去当前值 或 相当于是对数值求负后减1
  • 2.函数前加上波浪号,其作用是把函数声明转换为表达式,这样就可以直接运行。
~function sayHello(){
    console.log('hello');
}()
    1. indexOf中使用
用按位非操作符
if ( ~item[search_key].toLowerCase().indexOf(query) ) 
或
if ( !!~item[search_key].toLowerCase().indexOf(query) ) 
正常用法
if( str.indexOf(query) > -1 )
目前常用
if( str.include(query) )

“按位非”这中写法也许并非是效率最高的,表现最好的居然是我以前常用的写法,采用比较运算符。这确实让我很吃惊。有时候,人往往容易被常识,表象所迷惑,但亲自去尝试后,或许会有不一样的发现或得出其他的结果。今天,我算吸取教训了。

总结:

(1) JS中只能当做数值(不是数值会先转换为数值)进行位运算,与 ^(按位异或)、~(按位非)、<<(左移)、>>(右移)、>>>(无符号右移)功能一样,若操作数为非数值,则转换为数值。

(2) 若操作number的类型的NaN、-Infinity、Infinity则会被转换为数值0.

JavaScript中的按位操作符:

运算符 用法 描述
按位与( AND) a & b 对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
按位或(OR) a | b 对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
按位异或(XOR) a ^ b 对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
按位非(NOT) ~ a 反转操作数的比特位,即0变成1,1变成0。
左移(Left shift) a << b 将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
有符号右移 a >> b 将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。
无符号右移 a >>> b 将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

js任意进制转换

js做任意进制转化的核心函数是全局函数parseInt(str, radix)Number.toString(radix)

参考文档:parseInt

parseInt(str, radix)字符串str按照radix进制编码方式转换为radix进制返回,没有radix,默认为10;此方法把任意进制字符串转为10进制返回radix 为介于2-36之间的数。

注意: radix参数n会把第一个参数看作是一个数的n进制表示,而返回的值则是十进制的。例如

parseInt('123', 5) // 将'123'看作5进制数,返回十进制数38 => 1*5^2 + 2*5^1 + 3*5^0 = 38
console.log(parseInt('23',10)); // 23
console.log(parseInt('23',8));  // 19

Number.prototype.toString(radix)方法返回指定Number对象的字符串表示形式。radix指定要用于数字到字符串的转换的基数2-36,默认值为10。

参考文档:Number.prototype.toString()

let m = 20
let n = m.toString(10)
let q = m.toString(16)
console.log(n) // 20
console.log(q) // 14
console.log(typeof n) // string

m进制的数字num转为n进制,也就是任意进制的转换

function convert(num, m, n) {
   // 缺少异常处理
    let s = num + ''
    let result = parseInt(s, m).toString(n)
    return result
}

以上函数将m进制的num转换为n进制。其中,先用parseInt显示为10进制,再把10进制的数字用toString方法返回n进制的形式。