+! 运算符在if语句中

我正在审查一个angularjs工厂的代码,以更好地理解它是如何工作的。 代码包含一个if语句,我不完全理解。

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

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

它在github回购中略有不同:

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

显然通过错误消息它检查是否存在两个之一。 我只是不确定如何得出结论。 我一直没有find^+!任何信息+!

我的问题是:这个if语句是如何工作的? ( ^+!或者+!!具体)

!! 将值转换为布尔值( truefalse )。 +然后将该布尔转换为一个数字, 1true0为false。

 > +true 1 > +false 0 

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

 if (!config.template == !config.templateUrl) { throw ... } 

代码清晰度和可读性显然是可恶的。

+! 使用隐式转换来根据其布尔值将值转换为0或1

大多数情况下,这是为了检查是否存在。 例如,一个空string是假的( !!"" === false ),所以是未定义的,还有一些其他的。 这是主要的两个

“Falsey”转换

 +!!"" === 0 +!!false === 0 +!!0 === 0 +!!undefined === 0 +!!null === 0 +!!NaN === 0 

“Truthy”转换

 +!!1 === 1 +!!true === 1 +!!"Foo" === 1 +!!3.14 === 1 +!![] === 1 +!!{} === 1 

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

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

这里的真值表如下:

 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 

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

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

这是一个可怕的可读性方式来写出variables的布尔值,然后使用一元转换将其转换为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 

从技术上讲!! 不是它自己的操作符,它只是NOT( ! )操作符的两倍。

一元转换: ECMA spec doc一元加试图转换为整数。 Number()也是一个有效的转换。

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

处理小于2的数字时,如果考虑0 = false1 = true^将像布尔OR( || )一样工作。

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

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

所以,如果expression式是真的, +!!(expression)评估为1如果expression式是假的,则评估为0

 if ((+!!config.template) + (+!!config.templateUrl) !== 1) { 0 + 0 !== 1 true 0 + 1 !== 1 false 1 + 0 !== 1 false 1 + 1 !== 1 true 

等于

 if (!config.template === !config.templateUrl) { 

尽pipe这两个属性的内容。