I was reviewing the code for an angularjs factory to better understand how it works. The code contains an if
statement that I don't fully understand.
In a plnkr demo the author wrote this:
if ((+!!config.template) + (+!!config.templateUrl) !== 1) { throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`'); }
It is slightly different in the github repo:
if (!(!config.template ^ !config.templateUrl)) { throw new Error('Expected modal to have exactly one of either `template` or `templateUrl`'); }
Obviously by the error message it is checking to see if one of the two exists. I'm just not sure how it comes to the conclusion. I have not been able to find any information on ^
or +!
My question is: How does this if statement work? (^
or +!
or +!!
specifically)
When you combine each one of them with an IF statement, they read like this: AND – =IF(AND(Something is True, Something else is True), Value if True, Value if False) OR – =IF(OR(Something is True, Something else is True), Value if True, Value if False) NOT – =IF(NOT(Something is True), Value if True, Value if False)
In the logical AND ( && ) operator, if both conditions are true , then the if block will be executed. If one or both of the conditions are false , then the else block will be executed.
With the operator “OR,” if one of the conditions is met/True, the program will execute the true_code. If both conditions are false, the program will execute the false_code. It means that OR only returns TRUE if at least one of the conditions is met.
!!
converts a value to a boolean (true
or false
). +
then converts that boolean to a number, either 1
for true
or 0
for false.
> +true 1 > +false 0
Personally I find it clearer to write something like this, when dealing with two booleans:
if (!config.template == !config.templateUrl) { throw ... }
Code clarity and readability be damned, apparently.
+!! uses implicit conversion to cast a value as a 0 or 1 depending on its boolean value
For the most part, this is to check for existence. For example, an empty string is false (!!"" === false
), and so is undefined, and a number of others. Those are the main two though
"Falsey" conversions
+!!"" === 0 +!!false === 0 +!!0 === 0 +!!undefined === 0 +!!null === 0 +!!NaN === 0
"Truthy" conversions
+!!1 === 1 +!!true === 1 +!!"Foo" === 1 +!!3.14 === 1 +!![] === 1 +!!{} === 1
if ((+!!config.template) + (+!!config.templateUrl) !== 1)
Hopefully this is making more sense at this point. The object config
has two properties we are examining. .template
and .templateUrl
. The implicit cast to a 0 or 1 using +!!
is going to be added and then compared to ensure that it is not 1 (which means it is either 0 or 2) - the properties can either both be on or off but not different.
The truth table here is as follows:
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
A much simpler method to all of this would have been to just use the implicit boolean conversion
if (!config.template === !config.templateUrl)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With