~~它代表双非按位取反运算符,如果你想使用比Math.floor()更快的方法,那就是它了。需要注意,对于正数,它向下取整;对于负数,向上取整;非数字取值为0
!
!
在汉语里是一个语气的标点,在js中是个非运算符,ECMAScript 中这样定义:
产生式 UnaryExpression : ! UnaryExpression 按照下面的过程执行:
令 expr 为解析执行 UnaryExpression 的结果
令 oldValue 为 ToBoolean(GetValue(expr))
如果 oldValue 为 true, 返回 false
返回 true
因为js且是一个弱类型的语言,所以可以理解为执行了这样一个方法:
function ToBoolean(data){
if (Boolean(data) == true) {
return false
} else {
return true
}
}
具体细节我们不深究,详情在这ES5#9.2 ToBoolean
那么现在我们再说到!!这个运算符就好解释多了, !!的作用就是将操作数转化为布尔类型,例如:
!! null // false
!! undefined // false
!! '' // false
!! 'hello' // true
!! 5 // true
!! 0 // false
!! {} // true
!! 实际上等效于 Boolean 被当做函数调用的效果:
!!(value) === Boolean(value)
~
按位非操作符 ~
比逻辑非操作符 ! 复杂一些,作用是将数值比特位中的 1 变成 0,0 变成 1。ECMAScript 中的定义为:
产生式 UnaryExpression : ~ UnaryExpression 按照下面的过程执行:
令 expr 为解析执行 UnaryExpression 的结果
令 oldValue 为 ToInt32(GetValue(expr))
返回 oldValue 按位取反的结果
其中第二步分解为
令 number 为调用 ToNumber 将输入参数转化为数值类型的结果
如果 number 是 NaN,+0,-0,+∞ 或者 -∞,返回 +0
取整,如果是浮点数,会损失小数点后面的精度
转化为在 −2^31 到 2^31−1 之间的 32 位有符号整数并返回,调整到 32 位有符号整数区间内,如果整数原本不在这个区间,会丧失精度
那么 ~~ 实际上是 ~ 的简化版,因为第一次执行 ~ 时已经将操作数转化为 32 位有符号整数,第二次执行 ~ 时实际只是将按位取反的结果再次按位取反,相当于取消掉 ~ 处理过程中的第三步。那么 ~~ 的用途也就很明确了:将操作数转化为 32 位有符号整数。下面是例子:
~~ null // 0
~~ undefined // 0
~~ NaN // 0
~~ {} // 0
~~ true // 1
~~ '' // 0
~~ 'string' // 0
~~ '1' // 1
~~ Number.POSITIVE_INFINITY // 0
~~ 1.2 // 1
~~ -1.2 // -1
~~ 1.6 // 1
~~ -1.6 // -1
~~ (Math.pow(2, 31) - 1) // 2147483647 = 2^31-1
~~ (Math.pow(2, 31)) // -2147483648 = -2^31
~~ (-Math.pow(2, 31)) // -2147483648 = -2^31
~~ (-Math.pow(2, 31) - 1) // 2147483647 = 2^31-1
~~ (Math.pow(2, 32)) // 0
如果你需要将一个参数转化为 32 位有符号整数,那么 ~~ 将是最简便的方式。不过要切记,它会损失精度,包括小数和整数部分。