~运算符先将值强制类型转换成32位数字,然后执行字位操作“非”,~X大致等同于-(x - 1)。
~有以下用法:
一、与 indexOf() 方法共用
在-(x - 1)中唯一能够得到0的(严格来说是-0)的x值是-1,也就是说如果x为-1时,~和一些数字值在一起时会返回假值0,其他情况会返回真值。
-1是一个“哨位值”,哨位值是那些在各个类型中(这里是数字)被赋予了特殊的含义的值。比如,在C语言中,我们用-1代表函数执行失败,用大于等于0的值来代表函数执行成功。
JavaScript的字符串 indexOf() 方法也遵守这一惯例。该方法在字符串中搜索指定的子字符串,如果能找到就返回子字符串所在的位置(从0开始),否则返回-1。
indexOf() 方法不仅能得到子字符串的位置,还能用来判断字符串中是否包含指定的子字符串,相当于一个条件判断,例如:
var a = 'hello world';
if (a.indexOf('lo') >= 0) {
// true
}
if (a.indexOf('lo') != -1) {
// true
}
if (a.indexOf('ol') < 0) {
// true
}
if (a.indexOf('ol') == -1) {
// true
}
>= 0 和== -1这样的写法不是很好,称为“抽象渗漏”,意思就是在代码中暴露了底层的实现细节,这里指的是用 -1 作为失败的返回值,这些细节应该屏蔽掉。
~和 indexOf() 一起可以将结果强制类型转换(实际上仅仅是转换)为真/假值:
var a = 'hello world';
~a.indexOf('lo'); // -4 true
if (~a.indexOf('lo')) {
// true
}
~a.indexOf('ol'); // 0 false
!~a.indexOf('ol'); // true
if (!~a.indexOf('lo')) {
// true
}
如果用 indexOf() 返回-1,~将其转换成假值0,其他情况一律转换成真值。
二、字位截取
~~中的第一个~执行ToInt32并反转字位,然后第二个~再进行一次字位反转,即将所有的字位反转回原值,最后得到的仍然是ToInt32的结果。
很多人使用~~来截取数字值的小数部分,如:

但值得注意的是,负数是不可以使用的:

但我发现:

于是我得到了一个结论,~~x,x为正数时,~~x相当于Math.floor(x),x为负数时,~~x相当于Math.ceil(x)。
不过截取小数点的方法,使用x | 0似乎更好。