But I am not 100% happy with any of the answers as they all seem incomplete. So here we go again from first principles:
The user's overall aim:
Summarising the code: "I wish to add an error
class name to a string, optionally with a leading space if there are already class names in the string."
Simplest solution
As Kobi pointed out, five years ago, having a leading space in class names will not cause any problems with any known browsers, so the shortest correct solution would actually be:
h.className += ' error';
That should have been the actual answer to the actual problem.
Be that as it may, the questions asked were...
1. Why did this work?
h.className += h.className ? ' error' : 'error'
The conditional/ternary operator works like an if statement, that assigns the result of its true
or false
paths to a variable.
So that code worked because it is evaluated simply as:
if (h.className IS NOT null AND IS NOT undefined AND IS NOT '')
h.className += ' error'
else
h.className += 'error'
2. And why did this break?
h.className = h.className + h.className ? ' error' : 'error'
The question states "that gives a[n] error in my console", which may mislead you into thinking the code does not function. In fact the following code does run, without error, but it simply returns ' error' if the string was not empty and 'error' if the string was empty and so did not meet the requirements.
That code always results in a string that contains only ' error'
or 'error'
because it evaluates to this pseudocode:
if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
h.className = ' error'
else
h.className = 'error'
The reason for this is that the addition operator (+
to the common folk) has higher "precedence" (6) than the conditional/ternary operator (15). I know the numbers appear backwards
Precedence simply means that each type of operator in a language is evaluated in a particular predefined order (and not just left-to-right).
How to change the order of evaluation:
Now we know why it fails, you need to know how to make it work.
Some other answers talk about changing the precedence, but you can't. Precedence is hard-wired into the language. That is just a fixed set of rules... However, you can change the order of evaluation...
The tool in our toolbox that can change the order of evaluation is the grouping operator (aka brackets). It does this by ensuring the expressions in the brackets are evaluated before operations outside the brackets. That's all they do, but that's enough.
Brackets work simply because they (grouping operators) have higher precedence than all other operators ("there is now a level 0").
By simply adding brackets you change the order of evaluation to ensure the conditional test is performed first, before the simple string concatenation:
h.className = h.className + (h.className ? ' error' : 'error')
h.className += ' error'
, it also leaves a blank space at the beginning of the string if it was initially empty. I believe the point of the ternary operation is to produce a clean-looking string. – Auction