你不知道的js中卷 --- 奇特的~运算符

一个常被人忽视的地方是

~

运算符(即字位操作“非”)相关的强制类型转换,它很让人

费解,以至于了解它的开发人员也常常对其敬而远之。秉承本书的一贯宗旨,我们在此深

入探讨一下

~

有哪些用处。

2.3.5

节中,我们讲过字位运算符只适用于

32

位整数,运算符会强制操作数使用

32

格式。这是通过抽象操作

ToInt32

来实现的(

ES5

规范

9.5

节 )。

ToInt32

首先执行

ToNumber

强制类型转换,比如

"123"

会先被转换为

123

,然后再执行

ToInt32

虽然严格说来并非强制类型转换(因为返回值类型并没有发生变化),但字位运算符(如

|

~

)和某些特殊数字一起使用时会产生类似强制类型转换的效果,返回另外一个数字。

60

4

例如

|

运算符(字位操作“或”)的空操作(

no-op

0 | x

,它仅执行

ToInt32

转换(第

2

章中介绍过):

0 | -0; // 0

0 | NaN; // 0

0 | Infinity; // 0

0 | -Infinity; // 0

以上这些特殊数字无法以

32

位格式呈现(因为它们来自

64

IEEE 754

标准,参见第

2

章),因此

ToInt32

返回

0

关于

0 | ___

是显式还是隐式仍存在争议。从规范的角度来说它无疑是显式的,但如果对

字位运算符没有这样深入的理解,它可能就是隐式的。为了前后保持一致,我们这里将其

视为显式。

再回到

~

。它首先将值强制类型转换为

32

位数字,然后执行字位操作“非”(对每一个字

位进行反转)。

这与

!

很相像,不仅将值强制类型转换为布尔值

<

,还对其做字位反转(参

4.3.3

节 )。

字位反转是个很晦涩的主题,

JavaScript

开发人员一般很少需要关心到字位级别。

~

还可以有另外一种诠释,源自早期的计算机科学和离散数学:

~

返回

2

的补码。这样

一来问题就清楚多了!

~x

大致等同于

-(x+1)

。很奇怪,但相对更容易说明问题:

~42; // -(42+1) ==> -43

也许你还是没有完全弄明白

~

到底是什么玩意?为什么把它放在强制类型转换一章中介

绍?稍安勿躁。

-(x+1)

中唯一能够得到

0

(或者严格说是

-0

)的

x

值是

-1

。也就是说如果

x

-1

时,

~

和一些数字值在一起会返回假值

0

,其他情况则返回真值。

然而这与我们讨论的内容有什么关系呢?

-1

是一个“哨位值”,哨位值是那些在各个类型中(这里是数字)被赋予了特殊含义的值。

C

语言中我们用

-1

来代表函数执行失败,用大于等于

0

的值来代表函数执行成功。

强制类型转换

61

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 <--

真值

!

if (~a.indexOf( "lo" )) { // true

//

找到匹配!

}

~a.indexOf( "ol" ); // 0 <--

假值

!

!~a.indexOf( "ol" ); // true

if (!~a.indexOf( "ol" )) { // true

//

没有找到匹配!

}

如果

indexOf(..)

返回

-1

~

将其转换为假值

0

,其他情况一律转换为真值。

-(x+1)

推断

~-1

的结果应该是

-0

,然而实际上结果是

0

,因为它是字位操

作而非数学运算。

62

4

从技术角度来说,

if (~a.indexOf(..))

仍然是对

indexOf(..)

的返回结果进行

隐式

强制类

型转换,

0

转换为

false

,其他情况转换为

true

。但我觉得

~

更像

显式

强制类型转换,前

提是我对它有充分的理解。

个人认为

~

>= 0

== -1

更简洁

发布了235 篇原创文章 · 获赞 88 · 访问量 44万+

猜你喜欢

转载自blog.csdn.net/qq_34629352/article/details/105318981