+!if语句中的运算符

Jac*_*ack 42 javascript

我正在审查angularjs工厂的代码,以便更好地了解它的工作原理.该代码包含一个if我不完全理解的声明.

在一个plnkr演示中,作者写道:

if ((+!!config.template) + (+!!config.templateUrl) !== 1) {
  throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`');
}
Run Code Online (Sandbox Code Playgroud)

它与github repo略有不同:

if (!(!config.template ^ !config.templateUrl)) {
  throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`');
}
Run Code Online (Sandbox Code Playgroud)

显然,通过错误消息,它正在检查两者中是否存在其中一个.我只是不确定它是如何得出结论的.我无法找到任何关于^或的信息+!

我的问题是:这个if语句如何工作?(^+!+!!特异性)

Mat*_*all 72

!!将值转换为布尔值(truefalse). +然后转换该布尔值的数,或者1true0为假.

> +true
1
> +false
0
Run Code Online (Sandbox Code Playgroud)

就个人而言,在处理两个布尔值时,我发现写这样的东西更清楚:

if (!config.template == !config.templateUrl) {
  throw ...
}
Run Code Online (Sandbox Code Playgroud)

显然,代码清晰度和可读性受到了谴责.

  • 请注意,如果这两个确实是布尔值,那么你也可以写`if(config.template == config.templateUrl){}`...但是其中一个或两个可能是一个字符串,另一个是'undefined`或者`null`,这就是`!`运算符有所不同的原因.插入额外的行来分别捕获两个错误也是很好的; `if(template && templateUrl)抛出新错误("看到模板和templateUrl;你真的想要使用哪个?"); 如果(!template &&!templateUrl)抛出新错误("看不到模板也不看模板URL,我什么都没渲染!"); (4认同)
  • 我个人并不喜欢"+ !!",但值得注意的是,它会扩展到"预期"3个事件中的1个"更清晰地指定".在我看来,最可读的就是`if(truthyCount(item1,item2,item3)!== 1) (3认同)

Tra*_*s J 33

+!使用隐式转换将值转换为0或1,具体取决于其布尔值

在大多数情况下,这是为了检查是否存在.例如,空字符串是false(!!"" === false),因此未定义,还有许多其他字符串.这些是主要的两个

"虚假"转换

+!!""        ===   0
+!!false     ===   0
+!!0         ===   0
+!!undefined ===   0
+!!null      ===   0
+!!NaN       ===   0
Run Code Online (Sandbox Code Playgroud)

"Truthy"转换

+!!1         ===   1
+!!true      ===   1
+!!"Foo"     ===   1
+!!3.14      ===   1
+!![]        ===   1
+!!{}        ===   1
Run Code Online (Sandbox Code Playgroud)

if((+ !! config.template)+(+ !! config.templateUrl)!== 1)

希望这在这一点上更有意义.该对象config有两个我们正在研究的属性..template.templateUrl.隐式转换为0或1使用+!!将被添加,然后进行比较以确保它不是1(这意味着它是0或2) - 属性既可以打开也可以关闭但不同.

这里的真值表如下:

template    templateUrl    (+!!) + (+!!)     !==1
"foo"       "foo"              1 + 1         true
undefined   undefined          0 + 0         true
undefined   ""                 0 + 0         true
""          undefined          0 + 0         true
12          ""                 1 + 0         false
""          12                 0 + 1         false
undefined   "foo"              0 + 1         false
""          "foo"              0 + 1         false
"foo"       ""                 1 + 0         false
"foo"       undefined          1 + 0         false
Run Code Online (Sandbox Code Playgroud)

所有这一切的一个简单的方法就是使用隐式布尔转换

if (!config.template === !config.templateUrl)
Run Code Online (Sandbox Code Playgroud)


Ste*_*her 31

这是一种可怕的可读方式,用于写出变量的布尔值,然后使用一元转换将其转换为0/1数字结果.

考虑:

+!!true; //this converts true to false, then to true again, and true is 1 when converted
+!!0; //converts 0 (falsy) to true, then false, and then the numeric 0
Run Code Online (Sandbox Code Playgroud)

从技术上讲!!,它不是它自己的运算符,它只是NOT(!)运算符两次.

一元转换:ECMA规范doc一元加上尝试转换为整数.Number()也将是一个有效的转换.

  • 我经常听到"这段代码如此复杂/错综复杂/重要/如果你不知道如何解析这些操作符就像你的手背一样的理由,你不应该乱用这些代码. " 但老实说,我所听到的只是"让这个令人难以置信的复杂代码更难以解析!" (3认同)
  • 不正确.`parseInt(!! x)`与`+ !! x`不同.前者是"NaN".除了正确性,我不确定*可怕的可读性*基本原理是什么.`+ !! x`是多才多艺而且毫不含糊.(尽管Matt指出,整个表达式可以简化.) (3认同)

jrh*_*ath 6

同时,^是按位XOR运算符.

当处理小于2的数字时,如果你考虑= 和= ,^它将像布尔OR(||)一样工作.0false1true


Pau*_*aul 6

!是逻辑非运算符.它是一个一元运算符,它将其操作数转换为布尔值,然后将其否定.!!只是那个运算符两次,第二次!撤消否定,所以最终结果只是转换为布尔值.

+是一元加运算符,它将操作数转换为数字.在布尔值的情况下,false变为0,而true变为1.

因此,+!!(expression)评估1表达式是否真实,0如果表达式是假的.