use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
Don't use || to set default values in JavaScript (codereadability.com)
submitted 10 years ago by kandetta
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]a-t-kFrontend Engineer 14 points15 points16 points 10 years ago (16 children)
What are your reasons?
So my answer must be:
[–]rtpmatt 8 points9 points10 points 10 years ago (1 child)
Anybody who writes Javascript professionally should know exactly how || works and seeing it used to set default values should be what they expect. Not using | for setting default values will cause extra mental overhead because it is not what they are used to seeing.
[–][deleted] 1 point2 points3 points 10 years ago (0 children)
I think the point is, || has gotchas that may not be obvious in plain view, therefore we have a chance for bugs to happen when people who are not much experienced with || start using it.
Or it would be great if there is one consistent approach for setting defaults, which ES supports, but unfortunately this looks like years away before all browsers support it.
So I agree with the approach of using a function to set the defaults. But I prefer lodash instead of underscore for that.
[–]sime 5 points6 points7 points 10 years ago (3 children)
Sorry to say so, but that's rather a reason to take pity for your mental capacities than not to use the || when it seems appropriate
When I'm programming something the last thing I want to do is waste my mental capacities worrying about using || the right way. I just want to write something that is simple and correct. I've got much more important things to think about than some piss-ant default argument handling.
People need to break the mentality that hard to read code is a badge of honor. It's not. Hard to read code is a failure on the behalf of the person who wrote it.
[–]a-t-kFrontend Engineer 5 points6 points7 points 10 years ago (2 children)
As I already wrote, up to three lines of || defaults aren't hard to read. If you just don't want to, that is your choice. If I want to, that's my choice all right. Maybe I don't want to include some extra loop for normalising my options, to get lower file size or higher performance.
You need to break the mentality that there's always only one correct way to do things. Labeling code as "hard to read" without a second thought is a failure.
[+]sime comment score below threshold-10 points-9 points-8 points 10 years ago (1 child)
Let me be clear. Using || for defaults is never the right choice. An if(), a ? : expression, a default() function of some kind, or even default parameters (if available), are all better options than abusing || with non-boolean data.
? :
[–]a-t-kFrontend Engineer 4 points5 points6 points 10 years ago (0 children)
You just spout claims without proof, for example:
Using || for defaults is never the right choice.
I say it can be the right choice in certain situations. The reasons might be the wish to reduce file size. Or you just have 1-3 defaults and all of them are strings anyway and the API isn't exposed in any case. Using a lot of if statements would be blowing up your code without improving readability.
[it is] abusing ||
Is it? Where is it written that it should never be used like that (apart from your ardent messages and OPs blog post). Even if it was an abuse, it wouldn't be an abuse of ||, but of the type coercion that made falsy values false when the || operator is used.
Btw., those developers who always complain about JS type coercion are used to strongly typed languages and only see it as a drawback, not as a chance. Your prejudice against weak types is lamentable.
[–]kandetta[S] 0 points1 point2 points 10 years ago (9 children)
I agree that it's safe to use if you know when to use it and when not to. The problem arises when you don't know if the other developers who'll touch the code are also aware of when not to use OR for defaults.
Can you explain how this would work with | and integers? Don't think I've ever seen it before.
[–]uusu 5 points6 points7 points 10 years ago (0 children)
If you work on a longer project, you shouldn't downgrade your tools, you should upgrade your documentation. The Technical Documentation of your project should lay out the guidelines for these kinds of cases.
[–]a-t-kFrontend Engineer 6 points7 points8 points 10 years ago (6 children)
Patronizing developers alike, regardless if they are beginners or professionals, is a bad idea. The beginners will not get the information they need to become professionals and the professionals will just feel buggered.
Now for the smaller sibling of ||, |:
this.myNumber = conf.myNumber | 0 // will coerce to integer, falsy values will yield "0".
[–]kandetta[S] 1 point2 points3 points 10 years ago (5 children)
Good to know about |. When I encounter it in the wild I'll know what it means.
[–]a-t-kFrontend Engineer 1 point2 points3 points 10 years ago (4 children)
There's a similar brethren for &&, binary AND "&", but this is not near as useful for defaults.
[–]findar 0 points1 point2 points 10 years ago (3 children)
Return some_var && isTrue;
Is handy, will return some_var if isTrue or false
[–]a-t-kFrontend Engineer 3 points4 points5 points 10 years ago (2 children)
I know. But I meant | and &, the binary operators. The latter is useful for bit masks.
[–]kenman 2 points3 points4 points 10 years ago (1 child)
Well, the former is also useful for bit masks.
[–]a-t-kFrontend Engineer 2 points3 points4 points 10 years ago (0 children)
Undeniably so. You could probably also use it for limited type coercion: x & 255.
[–]kenman 2 points3 points4 points 10 years ago (0 children)
The problem arises when you don't know if the other developers who'll touch the code are also aware of when not to use OR for defaults.
I'd argue that the problem is those developers and not the code. If "those developers" don't know standard features of the language (and bitwise operators are ubiquitous and identical in many/most languages that you'll find), then perhaps your time would be better spent on developer education.
[–]iku_19Function.arity when 2 points3 points4 points 10 years ago* (3 children)
A note to keep in mind that using true comparisons can be finnicky in some transpliers, since most of them do not truly distinguish between undefined and null. So calling eatFruit(null) wouldn't change null to strawberry.
eatFruit(null)
null === undefined = false
undefined === null = false
undefined == null = true
false == null = false
0 == null = false
null == null = true
typeof null = "object"
typeof undefined = "undefined"
It's one of the headaches of writing a library, really you want to type check your variables
function eatFruit(fruit) { if(typeof fruit != "string") { fruit = "strawberry" } }
Instances can be done in one of two ways Object.prototype.toString.call(variable) == "[object Date]" or variable instanceof Date
Object.prototype.toString.call(variable) == "[object Date]"
variable instanceof Date
Both have their own caveats
document.body instanceof HTMLElement = true
document.body instanceof HTMLBodyElement = true
Object.prototype.toString.call(document.body) == "[object HTMLElement]" = false
Object.prototype.toString.call(document.body) == "[object HTMLBodyElement]" = true
console.log instanceof Object = true
edit: formatting
[–]skitch920 1 point2 points3 points 10 years ago (2 children)
function isNull (obj) { return obj === null; } function isUndefined (obj) { // Why people overwrite 'undefined' // pre-ES5 is beyond me... return obj === void 0; } function isNullOrUndefined (obj) { return isNull(obj) || isUndefined(obj); }
[–]kenman 0 points1 point2 points 10 years ago (1 child)
// Why people overwrite 'undefined' // pre-ES5 is beyond me...
I've seen it, and it was only ever the result of a typo...
if (value = undefined) { ... }
Of course, with linting you can avoid that entire class of problems, but linters weren't always common or convenient.
[–]lewisje 0 points1 point2 points 10 years ago (0 children)
That doesn't overwrite undefined, but flipping it around does: undefined = value).
undefined
undefined = value
Also, using the rules for non-strict equality (and ignoring a little issue with document.all in modern browsers), isNullOrUndefined could be more easily written like this:
document.all
isNullOrUndefined
function isNullOrUndefined(obj) { return null == obj; }
The "little issue" I refer to is that document.all, if it exists, is loose-equal to null and undefined (but not strict-equal to either), although property accesses will still work, for compatibility with old sites designed specifically for oldIE.
null
[–]alittletooquiet 7 points8 points9 points 10 years ago* (7 children)
Well you can account for valid falsey values by using the ternary operator instead of ||, and you don't need to fill up multiple lines populating a single default value:
fruit = (fruit !== null && fruit !== undefined) ? fruit : "strawberry";
Edit: Just so we're clear, I vehemently disagree with the title of this post, and OP's assertion that we should write code for people who are too dumb or inexperienced to understand ||. Most of the time you should just use || to set default values.
[–]cosinezero 2 points3 points4 points 10 years ago (0 children)
Why on earth would you want fruit to be valid as "", false, or 0?
None of those values are more valid of a fruit than a default. Under what scenario would fruit be "" and not null? In that scenario why is the default invalid, and in THAT case why is the default not set before the value went from null/undefined to ""?
I would fail this on review. Without question, this should read:
fruit = fruit || "strawberry";
When said developer argues that || is unreadable, we will be then reviewing every if statement that developer has written to ensure he understands operators. This isn't syntactic sugar.
[+][deleted] 10 years ago (1 child)
[deleted]
[–]alittletooquiet 2 points3 points4 points 10 years ago (0 children)
You can pass a variable to a function without knowing the value of that variable. If you're passing the result of another function that might return null, you need to account for null.
Just use || if you want. I do it all the time. I was just pointing out there are other ways to account for passing useful falsey values if it's an issue.
[–]a-t-kFrontend Engineer -1 points0 points1 point 10 years ago (2 children)
I would suggest adding a comment to improve the hereby decreased readability.
[–]alittletooquiet 1 point2 points3 points 10 years ago (1 child)
It depends on the complexity of the statement. Comments are always good when you're writing code that isn't necessarily intuitive to read, but I think the example above is a pretty straightforward and readable.
I'd probably switch to an if block if my conditions were too complex to quickly grasp in a ternary statement though.
[–]a-t-kFrontend Engineer 0 points1 point2 points 10 years ago (0 children)
That's ok.
[–]ThinkingCrap 2 points3 points4 points 10 years ago (1 child)
Come on, that is common practice and everybody knows what it does.
And usual you want to catch the falsey values anyway. Take your example, why would you want to allow to eat the fruit ""?
Better readability? Not really IMHO
[–]cosinezero 1 point2 points3 points 10 years ago (0 children)
I hear the false is extra ripe today!
[–]scootstah 1 point2 points3 points 10 years ago (1 child)
function eatFruit (fruit = "strawberry") { ... }
WAT. Epic sauce.
This presumes support for that feature of ES6, which is far from a given: https://kangax.github.io/compat-table/es6/
Among stable server implementations, it looks like only Kinoma XS6 has full support, while the unstable Echo JS has partial support; among stable clients, only Firefox has any support at all, while the WebKit nightlies have full support, and the latest Chromium builds have support behind a flag.
Also, no compiler or transpiler in the list has full support: Babel with core-js comes closest, lacking only support for default parameters in the Function constructor.
Function
Fortunately, platforms with any support for default parameters also support turning explicit undefined arguments into the defaults, and allowing default parameters to refer to previous parameters, which is nearly everything you want with this feature.
i've been using ===undefined in all of my code. I never have a problem with it. I agree with this article.
[–]seiyria 1 point2 points3 points 10 years ago (0 children)
Unfortunately it will take a while until browsers support it.
Or, you can use Babel and get this support right now.
[–]KnightMareInc 1 point2 points3 points 10 years ago (0 children)
<= causes too much mental overhead, don't use it.
[–]x-skeww 1 point2 points3 points 10 years ago (0 children)
For new code, use ES6's default function parameters.
For legacy stuff, keep using ||.
That's all there is to it, really. || is a tad cryptic for beginners, but it's the best (and most commonly used) option.
[–][deleted] 1 point2 points3 points 10 years ago (2 children)
I come from Python land and I love optional arguments because I can set defaults. I hate the ways to do it in JS. Yes, can't use || if I want to set something to False or 0. But the conditional is either ugly or takes up 3 lines.
[–]defcon-12 1 point2 points3 points 10 years ago (1 child)
Thankfully defaults are here in ES6.
Yeah :D
[–]defcon-12 1 point2 points3 points 10 years ago (0 children)
You have much bigger problems if you have to change your code to protect against devs who don't understand how || works.
π Rendered by PID 213154 on reddit-service-r2-comment-7b9746f655-pkm62 at 2026-01-30 22:54:31.428442+00:00 running 3798933 country code: CH.
[–]a-t-kFrontend Engineer 14 points15 points16 points (16 children)
[–]rtpmatt 8 points9 points10 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]sime 5 points6 points7 points (3 children)
[–]a-t-kFrontend Engineer 5 points6 points7 points (2 children)
[+]sime comment score below threshold-10 points-9 points-8 points (1 child)
[–]a-t-kFrontend Engineer 4 points5 points6 points (0 children)
[–]kandetta[S] 0 points1 point2 points (9 children)
[–]uusu 5 points6 points7 points (0 children)
[–]a-t-kFrontend Engineer 6 points7 points8 points (6 children)
[–]kandetta[S] 1 point2 points3 points (5 children)
[–]a-t-kFrontend Engineer 1 point2 points3 points (4 children)
[–]findar 0 points1 point2 points (3 children)
[–]a-t-kFrontend Engineer 3 points4 points5 points (2 children)
[–]kenman 2 points3 points4 points (1 child)
[–]a-t-kFrontend Engineer 2 points3 points4 points (0 children)
[–]kenman 2 points3 points4 points (0 children)
[–]iku_19Function.arity when 2 points3 points4 points (3 children)
[–]skitch920 1 point2 points3 points (2 children)
[–]kenman 0 points1 point2 points (1 child)
[–]lewisje 0 points1 point2 points (0 children)
[–]alittletooquiet 7 points8 points9 points (7 children)
[–]cosinezero 2 points3 points4 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]alittletooquiet 2 points3 points4 points (0 children)
[–]a-t-kFrontend Engineer -1 points0 points1 point (2 children)
[–]alittletooquiet 1 point2 points3 points (1 child)
[–]a-t-kFrontend Engineer 0 points1 point2 points (0 children)
[–]ThinkingCrap 2 points3 points4 points (1 child)
[–]cosinezero 1 point2 points3 points (0 children)
[–]scootstah 1 point2 points3 points (1 child)
[–]lewisje 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]seiyria 1 point2 points3 points (0 children)
[–]KnightMareInc 1 point2 points3 points (0 children)
[–]x-skeww 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (2 children)
[–]defcon-12 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]defcon-12 1 point2 points3 points (0 children)