I've recently become informed of the ternary operator and it seems like an effective way of cleaning up my code. However, I seem to be confused with the possibilities of it.
I understand that you cannot use it for if-only conditions, but I'm a little confused about the logic of what I've done.
I wrote this:
if(current_slide < 1){
current_slide = 1;
ToggleEnabled(next_button);
}else if(current_slide > total_slides){
current_slide = 1;
ToggleEnabled(prev_button);
}
It works, whatever. I wanted to clean it up a little, so I made this:
current_side < 1 ? (ToggleEnabled(next_button), current_slide = 1) : current_slide > total_slides ? (ToggleEnabled(prev_button), current_slide = 1) : [No clue what to put here];
Is there a better way of doing this in a more tidy way, or should I just keep using the if-elseif- ?
In my opinion the ternary operator should not be chained. As #VLAZ expressed their concerns in their comment, the ternary can become excessively difficult to read if you chain it in multiples. In this situation I would stick with the traditional if-else.
Take a look at the following:
if (condition1) {
// do stuff #1
} else if (condition2) {
// do stuff #2
} else if (condition3) {
// do stuff #3
} else {
// do stuff #4
}
And compare the readability to the same in ternary (I tried to indent it clearly, but chained ternary formatting is a matter of opinion):
condition1
? // do stuff #1
: condition2
? // do stuff #2
: condition3
? // do stuff #3
: // do stuff #4
To my eye the first option is a lot more readable. There is not much to be gained even if you would understand chained ternary very well, as it is (slightly) less efficient than traditional if-else.
Also of note should be the fact that ternary always needs the both the ? and the :, which means there is always a "final else" that you must deal with.
IMO, the ternary operator is meant to choose between answers or values, based on a condition, e.g.:
const x = condition1 ? 1 : 2;
return condition2 ? func1(x) : func2(x);
If you don't use the resulting value from a ternary expression (as you do) then the usage becomes highly suspect to me, and I would most likely ask it to be changed in code review. Even more so if you move the assignment part to BEHIND the ? and : selectors as you did.
Not everything that is possible, is also good style, good practice or recommended.
I just saw this construction for the first time in javascript
if (someConditionIsMet && !(anotherCondition && oneMoreCondition)) {
return something
}
There is a !() inside of the if-conditional statement. I'm wondering what exactly that does. Is it just a way of grouping several conditions together and making sure they all evaluate a certain way before triggering logic? If so, is this merely to simplify the appearance or is there some logical advantage here?
Specifically for !(anotherCondition && oneMoreCondition), it means NOT (anotherCondition AND oneMoreCondition).
This is De Morgan's laws:
not (A and B) = not A or not B
Some might say that not A or not B is easier to read than not (A and B) but that's personal preference.
Expanding the whole condition using De Morgan's law would result in:
someConditionIsMet AND (NOT anotherCondition OR NOT oneMoreCondition)
in Javascript:
if (someConditionIsMet && (!anotherCondition || !oneMoreCondition))
You can use that expanded form if you think it's more readable.
!() In any case in javascript means that if they are NOT true. So basically like in this case...
if(!(anotherCondition && oneMoreCondition)) {
Console.log("If both set to false this would run!");
}
if anotherCondition and oneMoreCondition were both set to false this would actually return true. This here might help you: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT_!
It's evaluating the condition of anotherCondition && oneMoreCondition, and then reversing it.
So if the condition evaluates to true, the ! makes the condition evaluate to false.
I found the following in a code example at datatables.net.
return value > 20 ? true : false;
Why wouldn't they have just written
return value > 20;
Could the latter return values other than true or false? Trying to figure out whether they were maybe just thinking the code was more readable this way, or whether there is actually a significant reason for doing this that I'm not aware of.
The only possible result is true or false. I don't think it makes it more readable. The only reason they may have done it that I can think of is that they were a new developer and didn't realize value > 20 was valid to return.
This is along the same lines as someone writing this:
if(value > 20 === true){ . . . }
Which is unnecessary because if conditions are implicitly compared against their "truthy-ness". The statement should be:
if(value > 20){ . . . }
As such, in your example, the code should just be:
return value > 20;
Because (as you correctly surmize) a greater-than/less-than expression can only result in true or false.
Now, if someone wanted to return an alternate set of binary results, then you could see something like this being used:
return value > 20 ? "acceptable" : "unacceptable";
Ok, while I was nesting some validation if, I've come into something about performance.
Let's suppose I'm validating a ticket to a show, I can do something like this:
var validateVipTicket = function (ticketInfo) {
if (ticketInfo.isPaid) {
if (ticketInfo.isOver16) {
if (ticketInfo.isVip) {
return true;
} else return 'Not Vip';
} else return 'Not old enought';
} else return 'Need to pay first';
};
And call it like this validateVipTicket({isPaid: true, isOver16: true, isVip: true});
BUT
let's suppose that does not matter to specify what error happened, I just want a true or false, then, what approach would be faster?
if (ticketInfo.isPaid) {
if (ticketInfo.isOver16) {
OR
if (ticketInfo.isPaid && ticketInfo.isOver16) {
On the first case, the first property will be checked and, when it finishes, the second property will be checked. On the second case, the first property will be checked, the second property will be checked and, them, both properties will be compared against each other. Is this right? Am I missing something? Which is faster and why?
On the second case, the first property will be checked, the second
property will be checked and, them, both properties will be compared
against each other. Is this right?
No, that's actually not right. The && operator does a short-circuit evaluation, which means that the second operand is never evaluated if the first operand evaluates to false.
That makes the two approaches exactly equivalent (even if there were any side effects of evaluating the oparands). As they do exactly the same amount of work in the same way, you can expect the performance to be very similar. It's even likely that the approaches end up generating the same executable code in the end.
It makes no difference:
if ( a && b )
is the same as
if ( a )
if ( b )
In the case of a && b, as soon as a is found false, then it does not matter what b is.
What happens at the CPU instruction level in both cases is:
cmp [a], 0 ; a == 0? (it does this by calculating a - 0)
jz false1 ; jump if result is zero
; a is true
cmp [b], 0
jz false2
; both a and b are true
Whether 3 different messages are returned, or just 1, could make a difference in speed, depending on how it is compiled. In this example, it makes no difference:
false1: return "not a!";
false2: return "not b!";
just_false: return false;
But here, an extra jump/goto is involved:
false1: result = "not a!"; goto done;
false2: result = "not b!"; // goto done optimized away
done: return result;
The 2 statements are equivalent in terms of performance. In both cases the second check (ticketInfo.isOver16) will be evaluated only if the first check (ticketInfo.isPaid) has returned true. Both statements are absolutely the same in terms of speed. So you should prefer the one that's more readable to you.
The performance in modern JS Engines such as V8 would be the same. Although there is always the chance that a crappy interpreter performs one better than the other but with modern browsers and JIT compilers such as V8 you should get the same results.
Proof of concept:
http://jsperf.com/nested-conditionals-vs-inline
I have a very long conditional statement like the following:
if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
// do something.
}
I was wondering if I could refactor this expression/statement into a more concise form.
Any idea on how to achieve this?
Put your values into an array, and check if your item is in the array:
if ([1, 2, 3, 4].includes(test.type)) {
// Do something
}
If a browser you support doesn't have the Array#includes method, you can use this polyfill.
Short explanation of the ~ tilde shortcut:
Update: Since we now have the includes method, there's no point in using the ~ hack anymore. Just keeping this here for people that are interested in knowing how it works and/or have encountered it in other's code.
Instead of checking if the result of indexOf is >= 0, there is a nice little shortcut:
if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
// Do something
}
Here is the fiddle: http://jsfiddle.net/HYJvK/
How does this work? If an item is found in the array, indexOf returns its index. If the item was not found, it'll return -1. Without getting into too much detail, the ~ is a bitwise NOT operator, which will return 0 only for -1.
I like using the ~ shortcut, since it's more succinct than doing a comparison on the return value. I wish JavaScript would have an in_array function that returns a Boolean directly (similar to PHP), but that's just wishful thinking (Update: it now does. It's called includes. See above). Note that jQuery's inArray, while sharing PHP's method signature, actually mimics the native indexOf functionality (which is useful in different cases, if the index is what you're truly after).
Important note: Using the tilde shortcut seems to be swathed in controversy, as some vehemently believe that the code is not clear enough and should be avoided at all costs (see the comments on this answer). If you share their sentiment, you should stick to the .indexOf(...) >= 0 solution.
A little longer explanation:
Integers in JavaScript are signed, which means that the left-most bit is reserved as the sign bit; a flag to indicate whether the number is positive or negative, with a 1 being negative.
Here are some sample positive numbers in 32-bit binary format:
1 : 00000000000000000000000000000001
2 : 00000000000000000000000000000010
3 : 00000000000000000000000000000011
15: 00000000000000000000000000001111
Now here are those same numbers, but negative:
-1 : 11111111111111111111111111111111
-2 : 11111111111111111111111111111110
-3 : 11111111111111111111111111111101
-15: 11111111111111111111111111110001
Why such weird combinations for the negative numbers? Simple. A negative number is simply the inverse of the positive number + 1; adding the negative number to the positive number should always yield 0.
To understand this, let's do some simple binary arithmetic.
Here is how we would add -1 to +1:
00000000000000000000000000000001 +1
+ 11111111111111111111111111111111 -1
-------------------------------------------
= 00000000000000000000000000000000 0
And here is how we would add -15 to +15:
00000000000000000000000000001111 +15
+ 11111111111111111111111111110001 -15
--------------------------------------------
= 00000000000000000000000000000000 0
How do we get those results? By doing regular addition, the way we were taught in school: you start at the right-most column, and you add up all the rows. If the sum is greater than the greatest single-digit number (which in decimal is 9, but in binary is 1) we carry the remainder over to the next column.
Now, as you'll notice, when adding a negative number to its positive number, the right-most column that is not all 0s will always have two 1s, which when added together will result in 2. The binary representation of two being 10, we carry the 1 to the next column, and put a 0 for the result in the first column. All other columns to the left have only one row with a 1, so the 1 carried over from the previous column will again add up to 2, which will then carry over... This process repeats itself till we get to the left-most column, where the 1 to be carried over has nowhere to go, so it overflows and gets lost, and we're left with 0s all across.
This system is called 2's Complement. You can read more about this here:
2's Complement Representation for Signed Integers.
Now that the crash course in 2's complement is over, you'll notice that -1 is the only number whose binary representation is 1's all across.
Using the ~ bitwise NOT operator, all the bits in a given number are inverted. The only way to get 0 back from inverting all the bits is if we started out with 1's all across.
So, all this was a long-winded way of saying that ~n will only return 0 if n is -1.
You can use switch statement with fall thru:
switch (test.type) {
case "itema":
case "itemb":
case "itemc":
case "itemd":
// do something
}
Using Science: you should do what idfah said and this for fastest speed while keep code short:
THIS IS FASTER THAN ~ Method
var x = test.type;
if (x == 'itema' ||
x == 'itemb' ||
x == 'itemc' ||
x == 'itemd') {
//do something
}
http://jsperf.com/if-statements-test-techsin
(Top set: Chrome, bottom set: Firefox)
Conclusion :
If possibilities are few and you know that certain ones are more likely to occur than you get maximum performance out if || ,switch fall through , and if(obj[keyval]).
If possibilities are many, and anyone of them could be the most occurring one, in other words, you can't know that which one is most likely to occur than you get most performance out of object lookup if(obj[keyval]) and regex if that fits.
http://jsperf.com/if-statements-test-techsin/12
i'll update if something new comes up.
If you are comparing to strings and there is a pattern, consider using regular expressions.
Otherwise, I suspect attempting to shorten it will just obfuscate your code. Consider simply wrapping the lines to make it pretty.
if (test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd') {
do something.
}
var possibilities = {
"itema": 1,
"itemb": 1,
"itemc": 1,
…};
if (test.type in possibilities) { … }
Using an object as an associative array is a pretty common thing, but since JavaScript doesn't have a native set you can use objects as cheap sets as well.
if( /^item[a-d]$/.test(test.type) ) { /* do something */ }
or if the items are not that uniform, then:
if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }
Excellent answers, but you could make the code far more readable by wrapping one of them in a function.
This is complex if statement, when you (or someone else) read the code in a years time, you will be scanning through to find the section to understand what is happening. A statement with this level of business logic will cause you to stumble for a few seconds at while you work out what you are testing. Where as code like this, will allow you to continue scanning.
if(CheckIfBusinessRuleIsTrue())
{
//Do Something
}
function CheckIfBusinessRuleIsTrue()
{
return (the best solution from previous posts here);
}
Name your function explicitly so it immediately obvious what you are testing and your code will be much easier to scan and understand.
You could put all the answers into a Javascript Set and then just call .contains() on the set.
You still have to declare all the contents, but the inline call will be shorter.
Something like:
var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}
One of my favorite ways of accomplishing this is with a library such as underscore.js...
var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
return test.type === item;
});
if(isItem) {
// One of them was true
}
http://underscorejs.org/#some
another way or another awesome way i found is this...
if ('a' in oc(['a','b','c'])) { //dosomething }
function oc(a)
{
var o = {};
for(var i=0;i<a.length;i++) o[a[i]]='';
return o;
}
of course as you can see this takes things one step further and make them easy follow logic.
http://snook.ca/archives/javascript/testing_for_a_v
using operators such as ~ && || ((),()) ~~ is fine only if your code breaks later on. You won't know where to start. So readability is BIG.
if you must you could make it shorter.
('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);
and if you want to do inverse
('a' in oc(['a','b','c'])) || statement;
Just use a switch statement instead of if statement:
switch (test.type) {
case "itema":case "itemb":case "itemc":case "itemd":
// do your process
case "other cases":...:
// do other processes
default:
// do processes when test.type does not meet your predictions.
}
Switch also works faster than comparing lots of conditionals within an if
For very long lists of strings, this idea would save a few characters (not saying I'd recommend it in real life, but it should work).
Choose a character that you know won't occur in your test.type, use it as a delimiter, stick them all into one long string and search that:
if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
// doSomething
}
If your strings happen to be further constrained, you could even omit the delimiters...
if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
// doSomething
}
...but you'd have to be careful of false positives in that case (e.g. "embite" would match in that version)
For readability create a function for the test (yes, a one line function):
function isTypeDefined(test) {
return test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd';
}
then call it:
…
if (isTypeDefined(test)) {
…
}
...
I think there are 2 objectives when writing this kind of if condition.
brevity
readability
As such sometimes #1 might be the fastest, but I'll take #2 for easy maintenance later on. Depending on the scenario I will often opt for a variation of Walter's answer.
To start I have a globally available function as part of my existing library.
function isDefined(obj){
return (typeof(obj) != 'undefined');
}
and then when I actually want to run an if condition similar to yours I'd create an object with a list of the valid values:
var validOptions = {
"itema":1,
"itemb":1,
"itemc":1,
"itemd":1
};
if(isDefined(validOptions[test.type])){
//do something...
}
It isn't as quick as a switch/case statement and a bit more verbose than some of the other examples but I often get re-use of the object elsewhere in the code which can be quite handy.
Piggybacking on one of the jsperf samples made above I added this test and a variation to compare speeds. http://jsperf.com/if-statements-test-techsin/6 The most interesting thing I noted is that certain test combos in Firefox are much quicker than even Chrome.
This can be solved with a simple for loop:
test = {};
test.type = 'itema';
for(var i=['itema','itemb','itemc']; i[0]==test.type && [
(function() {
// do something
console.log('matched!');
})()
]; i.shift());
We use the first section of the for loop to initialize the arguments you wish to match, the second section to stop the for loop from running, and the third section to cause the loop to eventually exit.