Personally, I find
return (foo && bar) || baz;
The most readable.
The top version just has too many curly braces and parentheses. I can keep each branch in mind easily, but keeping the whole program flow at once requires me to first parse it and translate it.
The last version, I can read as "either baz, or both foo and bar", which is easy to keep in mind at once, and would be much easier to pattern match for errors ("Oh no, I wanted foo and baz, not foo and bar") than the top version, for which I would possibly have to iterate each potential execution path in my mind to spot a mistake.
Consider, more concretely, (since I can't think of a better example), knowing whether to give someone an alcoholic drink. Let's go US style. Either they order a soda, or they are old enough and have ID. Three variables: isOver21, isSoda, isIdPresent.
(Putting aside the fact that the order here is weird and it could be designed better) we can either go:
if (isIdPresent) {
if (isOver21) {
return true;
}
}
if (isSoda) {
return true;
} else {
return false;
}
Or we can go:
return (isIdPresent && isOver21) || isSoda;
Now what if we accidentally swapped two variables:
if (isSoda) {
if (isIdPresent) {
return true;
}
}
if (isOver21) {
return true;
} else {
return false;
}
vs
return (isSoda && isIdPresent) || isOver21;
Note how in the first case, if I am tired, I could miss it. Most of the code paths seem correct. If someone is ordering a soda and has an ID they should get the drink. If they are not ordering a soda, and they aren't over 21, they shouldn't get anything. If they are over 21, they should probably get something.
In the second case, I can see all the logic in one line, and I can say "hold up, why are we asking for soda and ID, or age? Something seems off." Not that I can't do that with the multi-line if, just that it might take a bit longer.
Source: I've been bitten by multi-stage if statements on a few occasions.