Using &&'s short-circuiting as an if statement? - javascript

I saw this line in the jQuery.form.js source code:
g && $.event.trigger("ajaxComplete", [xhr, s]);
My first thought was wtf??
My next thought was, I can't decide if that's ugly or elegant.
I'm not a Javascript guru by any means so my question is 2-fold. First I want to confirm I understand it properly. Is the above line equivalent to:
if (g) {
$.event.trigger("ajaxComplete", [xhr, s]);
}
And secondly is this common / accepted practice in Javascript? On the one hand it's succinct, but on the other it can be a bit cryptic if you haven't seen it before.

Yes, your two examples are equivalent. It works like this in pretty much all languages, but it's become rather idiomatic in Javascript. Personally I think it's good in some situations but can be abused in others. It's definitely shorter though, which can be important to minimize Javascript load times.
Also see Can somebody explain how John Resig's pretty.js JavaScript works?

It's standard, but neither JSLint nor JSHint like it:
Expected an assignment or function call and instead saw an expression.

You must be careful because this short-circuiting can be bypassed if there is an || in the conditional:
false && true || true
> true
To avoid this, be sure to group the conditionals:
false && (true || true)
> false

Yes, it's equivalent to an if as you wrote. It's certainly not an uncommon practice. Whether it's accepted depends on who is (or isn't) doing the accepting...

Yes, you understand it (in that context); yes, it is standard practice in JavaScript.

By default, it will trigger a jshint warning:
[jshint] Expected an assignment or function call and instead saw an expression. (W030) [W030]
However personally, I prefer the short-circuit version, it looks more declarative and has "less control logic", might be a misconception though.

Related

Comparison operator giving idiosyncratic result in JavaScript

A friend of mine today told me to open the Chrome Console and see the output for three JavaScript commands that I report here below (with the corresponding output).
> Boolean([])
< true
> Boolean("")
< false
> [] == ""
< true
When I told him that it was probably a bug, he replied that it is a famous thing and a JavaScript developer should know about it.
Is it true? Is there any logic that justifies the output seen above or it is just a bug of the language?
To compare [] and "", JavaScript tries to bring them to same type, in this case: String.
You'll notice a similar result with this (and it makes sense to us):
[].toString() == "" // true
Wow! What a great question! This is such crazy behavior when coming to JavaScript from a different language right? Or heck, even if JavaScript is your first language it's still crazy. But it is indeed the language working as intended.
There's an amazing answer/explanation of this behavior and why it happens here. In a nutshell, JavaScript does a lot of type casting and interesting things under the hood when you use the equality operator (==). More often, you'll probably want to be using the identity operator (===) as it performs stricter comparison and JavaScript doesn't attempt to do any type-casting or magic beneath the surface when using it.
Double equals performs type coercion. It'll attempt to convert each one to a common type before checking equality. This is why it's recommended JavaScript developers always use triple equals(===) which performs a strict type equality comparison.
In this case, [] will be converted to an empty string which is considered falsy like the empty string it's being compared to. The same situation can be seen in the example below:
[5]==5
true

OK to use type coercion when checking for undefined/null?

Is it acceptable to use type coercion (== instead of ===) to check for undefined/null?
What are the downsides? Is there a better way to check for undefined/null?
Clarification: I am looking for a statement that will check for both undefined and null.
test(null);
test(undefined);
function test(myVar) {
if (myVar != undefined) {
alert('never gets called')
}
}
I'm going to attempt to address this question as objectively as possible, but it deals with some mushy "best practices" opinion stuff that can trigger people to forget that there's more than one way to do things.
Is it acceptable to use type coercion (== instead of ===) to check for undefined/null?
It's acceptable to write code however you see fit regardless of anyone who tells you otherwise. Including me.
That's not really helpful here, so let me expand on that a bit, and I'll let you decide how you feel about it.
Code is a tool that can be used to solve problems, and == is a tool within JavaScript code to solve a specific problem. It has a well-defined algorithm which it follows for checking a type of equality between two parameters.
===, on the other hand, is a different tool that solves a different, specific problem. It also has a well-defined algorithm which it follows for checking a type of equality between two parameters.
If one tool or the other is appropriate for your use-case, then you shouldn't hesitate to use the tool.
If you need a hammer, use a hammer.
But if all you have is a hammer, then everything looks like a nail, and this is the core issue with ==. Developers coming from other languages often aren't aware of how == works and use it when === would be appropriate.
In fact, most use cases are such that === should be preferred over ==, but as you've asked in your question: that's not true in this instance.
What are the downsides?
If you relax your standards for === and allow developers to use == you may very well get bitten by misuse of ==, which is why sticking religiously to === may be acceptable to some, and seem foolish to others.
if (val === null || val === undefined) {...
is not particularly difficult to write, and is very explicit about intent.
Alternatively,
if (val == null) {...
is much more concise, and not difficult to understand either.
Is there a better way to check for undefined/null?
"better" is subjective, but I'm going to say, "no" anyway because I'm not aware of any that improve the situation in any meaningful way.
At this point I will also note that there are other checks that could be performed instead of null/undefined. Truthy/falsey checks are common, but they are another tool used to solve yet another specific problem:
if (!val) {...
is much more concise than either of the previous options, however it comes with the baggage of swallowing other falsey values.
Additional notes on enforcement via linting:
If you follow the strictness of Crockford's JSLint, == is never tolerated, in the understanding that a tool that's "sometimes useful" but "mostly dangerous" isn't worth the risk.
ESLint, on the other hand, allows for a more liberal interpretation of the rule by providing an option to allow null as a specific exception.
== undefined and == null are both equivalent to checking if the value is either undefined or null, and nothing else.
As for "acceptable", it depends on who is looking at the code, and whether your linter is configured to ignore this special case.
I can tell you for sure that some minifiers already do this optimisation for you.
The ideal way to test for undefined is using typeof. Note you only need to test them separately if you care about a difference between undefined and null:
test(null);
test(undefined);
function test(myVar) {
if (typeof myVar === "undefined") {
// its undefined
}
if (myVar === null) {
// its null
}
}
If you don't care if its undefined/null, then just do:
test(null);
test(undefined);
function test(myVar) {
if (!myVar) {
// its undefined or null, dunno which, don't care!
}
}

Is it bad practice to utilise JavaScripts "truthiness"?

Underscore.js has two methods _.isNull and _.isUndefined which we use a lot in our code and we've also created a mix-in for _.isUndefinedOrNull.
I recently realised that I could easily use javascripts "truthiness" to achieve the same results most of the time so the question is, is that considered bad practice?
What's better?
if(someVariable){...}
or
if(_.isNull(someVariable) || _.isUndefined(someVariable){...}
They both are entirely different.
if (someVariable)
will evaluate to falsy, if someVariable is 0 or false. So it is better to have explicit checks in this case. You might like to check the truth table in this answer which shows when a variable will be evaluated to either truthy or falsy.
I recently realised that I could easily use javascripts "truthiness" to achieve the same results most of the time
If only most of the time, then your solution doesn't work. Use if (someVariable == null) instead to test for either undefined or null.
so the question is, is that considered bad practice?
Not necessarily. If you know that all the possible values for someVariable other than the null/undefined you want to test for are truthy (e.g. objects), then it's fine.
If they can be primitive values, it's usually a mistake except your condition explicitly wants to test for the falsy values of the respective type. In your null-comparison case it would a mistake.

Is there a way to conditionally call a function with one line of JavaScript?

I would like an elegant way to only execute a function if some condition is met. Two options that I know of are if conditions and the tertiary operator.
if
if(headerExists($listview) === false)
addHeader($listview, template);
tertiary
headerExists($listview) ? null : addHeader($listview);
To me, the if makes the logic a little harder to understand when you look at the function as a whole. The tertiary function seems smart but you never see it anywhere and having to declare null is explicitly wasted space.
The third option is to (ab)use the short-circuit behaviour of the logical operators:
!headerExists($listview) && addHeader($listview, template);
// or
headerExists($listview) || addHeader($listview, template);
However, this is only a minification technique (which doesn't even make the code a lot shorter). Use an if-statement for readability reasons, if you want without a block and in one line:
if (!headerExists($listview)) addHeader($listview, template);

Assigning JavaScript primitives to their named equivalent variable like "constants"

I was looking at the source code to qTip 2 and saw the following:
// Munge the primitives - Paul Irish tip
var TRUE = true,
FALSE = false,
NULL = null;
I can't come up with a reason you should ever do this, and have a strong feeling that it would just encourage bad coding habits. Say a developer makes a typo in a Yoda condition like if (TRUE = someCondition()), then TRUE could very well end up actually meaning false, or you might end up assigning someObject to NULL.
I guess I'm just wondering if there's some redeeming quality for this practice that I'm missing, or if this is just a plain old Bad Idea™
The goal of this is just to improve compression, Paul Irish himself calls it as an "Anti-Pattern".
He describes it as "Good for compression and scope chain traversal" on the following presentation:
jQuery Anti-Patterns for Performance & Compression (slide 46)
On scope chain traversal, we won't see any improvement on literals as null, false, true, since the scope chain is not inspected, they are just literals.
On other identifiers as undefined or windows the scope chain traversal is indeed inspected.
You could do this for the sake of code compression. For example, YUI Compressor is not going to touch true and false, but it could replace all occurrences of, for example, TRUE with A, saving four characters per occurrence. For example, before compression:
if (foo === null) {
bar = true;
}
After compression, assuming the compressor replaces TRUE with a and NULL with c:
if(foo===c){bar=a;}
Versus this, after compression with no "munging of primitives":
if(foo===null){bar=true;}
The bad-coding-habits danger that you quite correctly cite in your question may outweigh the small savings in additional compression. It depends on how desperate you are to save a few dozen or perhaps a few hundred bytes.
Personally, I would (almost) never do this. Too dangerous.
I believe this is recommended for compression.
These shortcut variables will be compressed when munged, resulting in smaller files. However, your noted drawbacks are most certainly valid points!

Categories

Resources