今天在项目中看到有这样一段代码: java
if(~key.indexOf('I')){
priceTagData.adulti = {
tag: key,
price: value
}
}
我表示对~这个操做符感到无比陌生,天然也就理解不了做者的意图。因为目前本人的求知欲正处于旺盛期,因此决定学习一下这个操做符的用处。ios
看了眼ES5,原来它是位取反操做符。下面是ES5对这个操做符的说明: c++
![]() |
Bitwise NOT Operator ( ~ ) The production UnaryExpression : ~ UnaryExpression is evaluated as follows:编程 1.Let expr be the result of evaluating UnaryExpression. |
大概求值过程就是:学习
1.先求值~右边的表达式,设求值结果为exprlua
2.执行ToInt32(expr),设返回结果为oldValuespa
![]() |
由于ECMAScript中Number类型存储格式是64位浮点数,因此在进行位操做前要把浮点数转换为32位有符号整数,也就是上边说明中的ToInt32方法。ToInt32是规范定义的内部类型转换方法,ECMAScript程序使用者不能直接调用,ToInt32具体说明点这里 。 |
3. 将oldValue按位取反并返回code
因为返回的是32位整数,因此还须要将这个整数转换为64位浮点数。因而可知,ECMAScript中的位操做并不像c,c++那样直接操做位,它须要在位操做以前和以后进行浮点数转成整数和整数转成浮点数的操做。索引
看一个具体例子:~4294962318,咱们经过上边规范的定义来意淫下结果。。。
首先求值~右边的表达式,求值后就是4294962318,
而后执行ToInt32(4294962318),
ToInt32的内部执行过程为:
将4294962318进行ToNumber转换,结果依旧为4294962318
求值sign(4294962318) * floor(abs(4294962318)),结果依旧为4294962318
求值4294962318 modulo 4294967296(2^32)的值,结果为4294962318
4294962318 大于2147483648(2^31),因此返回4294962318 - 4294967296,也就是-4978
接下来要把-4978转换成2进制,为了方便我写了段程序把一个10进制转换成2进制,下边是c++源码,你能够经过这个程序转换你想转换的数字
#include <iostream>
using namespace std;
int main () { int t; cout << "输入一个要转换为2进制表示形式的数字:"; cin >> t; char str[255]; itoa(t, str, 2); cout << str << endl; system("pause"); return 0; }
-4978用二进制表示为 1111 1111 1111 1111 1110 1100 1000 1110
按位取反后就是 0000 0000 0000 0000 0001 0011 0111 0001
这个取反后的结果理论上就是~4294962318计算出的值
接下来咱们在js控制台执行~4294962318,获得4977
再用程序将4977转换成二进制结果是0000 0000 0000 0000 0001 0011 0111 0001
你会发现和咱们推导出的二进制是同样的
理论和实践都讲过以后,咱们再回到最初的问题:
if(~key.indexOf('I')) {
做者这句到底想要干什么。。。
indexOf你们应该都知道,它是字符串的一个方法,用来查找传入的字符在字符串中第一次出现的位置,若是有,则返回该字符在字符串中的索引值,若是没有返回-1。
~-1正好等于0,而0在ECMAScript if条件中又至关于false,非0数都至关于true。终于!!!我明白了做者的意图,那就是若是key字符串中若是含有I那就执行if条件为true中的语句,若是不含有I,那就不执行if条件为true中的语句。
和这种高帅富写法等效的屌丝写法就是:
if(key.indexOf('I') !== -1){
saveTheEarth();
}
最后就是吐槽时间了。。。
我我的不是很同意这种怪异的写法(相对于我)。由于jser在平时编程中须要使用位操做的地方还算比较少的,因此在多人项目中若是写了这样一句代码,往后别人来维护这块代码时就会感到一头雾水,无形中增长了项目维护的难度和成本。