When writing code, it is always better to be as explicit as possible instead of going for tricks. This concept is best explained by examples so let's get right into it.
The double bang !! (logical NOT)
This one is by far the most common "trick" in the JavaScript world. So much so that it is actually taught to developers as they learn about logical operators in JavaScript and can be found in Mozilla's official documentation (MDN). If you wish to obtain a primitive boolean (true
or false
) from a non-boolean entity, you can use the logical NOT operator as follows:
const primitiveBoolean = !!notABoolean;
If notABoolean
is truthy in the example above, primitiveBoolean
will contain the value true
and if it is falsy, primitiveBoolean
will be false
.
You can get the same results by using the Boolean()
function and get a much more readable version of the code.
const primitiveBoolean = Boolean(notABoolean);
Does the double bang way provide any benefit? The correct answer is no, but it does carry the disadvantage of making your code less readable. This trick (like many others) works because of JavaScript's type coercion. Let's look at the spec to see how the logical NOT operator (!) works.
As can be seen, after the expression is evaluated and a final value is obtained, this final value is passed through an algorithm to get the final value's boolean equivalent. This algorithm is represented by ToBoolean()
in the spec and is basically just a series of conditions to determine the boolean equivalent of a value (you can see the exact steps by clicking on ToBoolean
on the spec's page). Once this is done, next step is what the NOT operator is supposed to do: return false
if the evaluated value is true
and true
otherwise. The second NOT operator then inverts this value to finally give the correct result (and we end up with the double bang !!).
Now let's see how the Boolean()
function works.
So when Boolean()
is called as a function, as opposed to a constructor (i.e. with the new
keyword), it performs a simple type conversion. This type conversion is done using the same algorithm, ToBoolean()
, discussed above.
In both cases, your code is performing the same task behind the scenes. If anything, the double bang trick has an extra step of inverting the value obtained by the first operation. While using Boolean()
results in a much more elegant and readable code.
The unary + operator
Wish to convert a string representation of a number to an actual number? Just precede it with a +
like so:
const myData = +"123";
console.log(typeof myData); // output: "number"
This gives us even more obscure code than the double bang trick discussed above. Still, this might prove to be controversial as even the MDN docs say that this is the "preferred" method to convert a string to a number. Let's look at the alternative:
const myData = Number("123");
console.log(typeof myData); // output: "number"
Just as we had used Boolean()
as a function to get a primitive boolean value, we have used Number()
as a function here to convert the string to a number. The details behind the scenes here are exactly the same as before except the fact that instead of ToBoolean
, the algorithm used for type conversion is called ToNumber
in this case.
The MDN docs say that using the unary + operator is the fastest method but the specs tell us a different story. Both +
and Number()
use the exact same algorithm to do the type conversion but the latter results in a much more readable code.
The magic numbers
This one isn't related to type conversion but is seen relatively frequently. Magic numbers are the use of numbers directly in your code. It is more preferable to declare a well-named variable and assign it the desired value than to use the number directly.
if (password.length < 6) {
throw new Error("Password must be more than 5 characters long");
}
Considering the code above, a much better approach would be:
const MIN_PASSWORD_LENGTH = 6;
if (password.length < MIN_PASSWORD_LENGTH) {
throw new Error(`Password must be more than ${MIN_PASSWORD_LENGTH - 1} characters long`);
}
The first and obvious advantage here is that the code is now much more readable. Another potential advantage would be in the case where the same constraint is utilized in multiple places (which happens fairly often). If the constraint later changes, you'll only have to update it at one location.
If there is a direct number in your code, strongly consider declaring a constant and using it instead. Most of the times this will be the correct approach. Although there are some edge cases where using the number directly might be the preferable.
if (transactions.length > 0) {
// show transactions
} else {
// show msg: "No transactions"
}
The above code is perfectly readable and there seems to be no reason to declare a separate variable for the value 0.
Conclusion
When writing code, readability should be a priority. The tricks/shortcuts usually add no benefit, performance or otherwise, and make the code considerably less readable. So, always go for a more explicit option.
👉🏻 Subscribe to my newsletter: click here
👉🏻 Follow me on twitter: click here
Top comments (12)
I pretty much agree with this, but what is and isn't a trick is largely a matter of perception, and may change with time. Specifically, I remember learning
!!
to convert something to a boolean, and I didn't regard it as a trick. To me, it was just the way you convert something to a boolean. It's what I and the people around me did. I don't think I even knew aboutBoolean()
then.I think the perception that it's a fancy trick is one that has grown and become more common over time. Now I too regard it as one, and use
Boolean()
instead.That is exactly what we wish to rectify.
Very bad idea. Will only drag down the quality of developers over time.
Teach people all about the language, don't blindly preach dogma and opinions. Show them the ins and outs of it, how it works, and different ways of doing the same things. Don't patronise them and treat them like children unable to make decisions about which way to do it is best for them or their project.
Readability is purely subjective, and marking parts of the language as 'off limits' or 'bad practice' inhibits knowledge, and potentially the performance of software.
It's this kind of thinking that has progressively dragged down and overcomplicated software over the past decade or more, particularly in web development.
A lot of the time, they do add performance benefit - and it can be considerable (a quick test showed
!!
to be consistently faster thanBoolean
- more than twice as fast in fact)Boolean is as fast as !!. Your test is not accurate.
github.com/solidjs/solid/pull/500#...
Run this in both Chrome and Firefox.
!!
is faster in both, and on Firefox it is almost twice as fastIf you want the simplest test possible, try this - not quite such a pronounced difference, but
!!
still fasterNot for me.
dev-to-uploads.s3.amazonaws.com/up...
Interesting. It's faster for me both on Mac, Linux, and Android - on both Firefox and Chrome
That is some quality input. Appreciated!
Just a side note about type casting. Kind of have to deal with it in JavaScript since all incoming data from the DOM is of type string!
I agree with all your points, but could you change the links to something more descriptive than, "click here"?
A screen reader listing links out will speak them all the same.
Thanks for highlighting this. I've updated the link texts.