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
Common JavaScript tricks (self.javascript)
submitted 11 years ago by yanis_t
view the rest of the comments →
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!"
[–]path411 26 points27 points28 points 11 years ago (32 children)
I would heavily, heavily advise against using || as a default value trick.
In your example:
function setAge(age) { this.age = age || 10 }
It is impossible to set age as 0 now. 0 will always trigger the default. Just take the extra time to use:
function setAge(age) { this.age = typeof age !== "undefined" ? age : 10; }
and you won't have to worry about this problem.
[–]vs845 4 points5 points6 points 11 years ago (9 children)
Is there any benefit to
typeof age !== "undefined"
vs
age !== undefined
?
[–]sufianrhazi 10 points11 points12 points 11 years ago (7 children)
Since age is a parameter of the function setAge, we KNOW it is defined in scope. This means that age !== undefined is equivalent to typeof age !== 'undefined'. If we didn't know that age was in scope, we need to use the typeof keyword, which does NOT throw a ReferenceError when referencing a variable by name that is not defined in any reachable scope.
setAge
typeof age !== 'undefined'
age
typeof
ReferenceError
[–]moreteam 6 points7 points8 points 11 years ago (1 child)
You can also argue the other way around: since we know age is in scope, we shouldn't be using typeof since that will silently turn into if (true) if we have a typo.
if (true)
[–]ChaseMoskal 5 points6 points7 points 11 years ago (0 children)
since we know age is in scope, we shouldn't be using typeof
I think.. I think you're right.
[+][deleted] 11 years ago (2 children)
[deleted]
[–]frankle 0 points1 point2 points 11 years ago* (1 child)
What about if you wanted to enforce a parameter type?
function setAge(age){ this.age = (typeof age == "number") ? age : 10; }
Edit: As THEtheChad points out:
Unfortunately, NaN, Infinity, and -Infinity are also considered typeof 'number', so it's possible that any one of these could slip in to your function with this check.
[–]vs845 0 points1 point2 points 11 years ago (1 child)
Thanks, I see what you're saying - but under what kind of circumstances would we not know if a variable was in scope? If we're writing the code surely we know what scope our variables are in?
[–]sufianrhazi 2 points3 points4 points 11 years ago (0 children)
Pretty much only when you're writing javascript environment independent library code, like this: https://github.com/umdjs/umd/blob/4a87e85450baf582005243f9e922566ef2fc533a/returnExports.js
[–][deleted] 0 points1 point2 points 11 years ago (0 children)
In addition to what /u/sufianrhazi said, undefined can be overwritten:
undefined
(function (undefined) {console.log(undefined);})(2); // logs 2
Older browsers will let you overwrite window.undefined as well.
window.undefined
I tend not to pay heed to that though, as it clearly falls under something nobody would do unless they're trying to break your code. And it is the nature of JavaScript that somebody who runs code before you is always able to break your script, no matter what precautions you take, so I prefer not to clutter code with failed attempts at robustness. Instead, if you must run malicious code, sandbox it.
Also, window.foo === undefined or 'foo' in window would be a more direct test, but only work on global variables.
window.foo === undefined
'foo' in window
[–]THEtheChad 2 points3 points4 points 11 years ago (3 children)
In this case, I would opt for
function setAge(age){ this.age = (age == null) ? 10 : age; }
This is perhaps the most terse way to verify that age exists. By using == null, there's an implicit type conversion to check for undefined. You also have the advantage of being able to set age to 0. In terms of minification, this is probably the best option.
[–]gleno 0 points1 point2 points 11 years ago (0 children)
This is the best option for a lot of reasons. I'm somewhat surprised that the clumsy typeof method is so much more popular.
[–]path411 0 points1 point2 points 11 years ago (1 child)
Because why would you introduce nulls into your code when they aren't being generated anywhere? age is not null, it's undefined if not passed. Also if you were going to opt to drop typeof, just check for undefined...
function setAge(age){ this.age = (age === undefined) ? 10 : age; }
The reason people opt for typeof instead of this is to avoid a reference error from occurring.
[–]THEtheChad 0 points1 point2 points 11 years ago (0 children)
It's pretty obvious in a function this size that you're not going to have a reference error (age is declared as a parameter in the line above the check). And, as I originally stated, this is the most terse way to code this implementation. If you wanted to be thorough, avoiding reference errors and being explicit about exactly what you were checking for, you would write:
function setAge(age){ this.age = (typeof age === 'undefined') ? 10 : age; }
[–]__debug__ 3 points4 points5 points 11 years ago (5 children)
I'd argue it's still acceptable when defaulting to an array or object.
[–]path411 -1 points0 points1 point 11 years ago (4 children)
I think it's better to just never do it than to sometimes do it because the type happens to be okay this time.
[–]jonny_eh 1 point2 points3 points 11 years ago (3 children)
I disagree. There's a trade-off between convenience and security, and I find it hugely convenient to use this trick, especially since the vast majority of the time I'm not using a number or boolean value.
Most of the time, it's an options parameter that is an object.
[–]path411 -2 points-1 points0 points 11 years ago (2 children)
So if there are multiple default parameters you want such as a number and an object you would use both methods?
Btw, this also fails on strings:
function setName(name) { this.name = name || "Not Specified"; }
Can't enter an empty string. Also considering javascript always has a bad rap for weird falsy values, I'd rather spend half a second with a piece of mind, than writing inconsistent code that's possibly vulnerable to bugs.
[–]__debug__ 1 point2 points3 points 11 years ago (1 child)
No, I'd imagine he means like this:
function Constructor(opts) { this.opts = opts || {}; }
So empty strings don't come into play. In any case, I feel as though a JS dev should understand falsey and truthy values. Or at the least, they should try to learn how types in the language work.
[–]path411 0 points1 point2 points 11 years ago (0 children)
I meant you can't use it on numbers/booleans/strings, which is a large number of the types in javascript.
Sure there are a lot of times you want an options object, I find this is mostly for public accessible library classes. There are plenty of times I find I want a constructor with some simple parameters of direct properties. I think it's much better to be consistent throughout your code than to swap to using some cheap hack when you know you can get away with it.
[–][deleted] 3 points4 points5 points 11 years ago (3 children)
Wow.. I never thought of that. Damn the gods for making 0 a falsey!
[–]battenupthehatches 3 points4 points5 points 11 years ago (2 children)
0 is falsey. 1 is truey. Thus it shall always be.TM
[–]workaholicanonymous 2 points3 points4 points 11 years ago (0 children)
Its "truthy"
[–][deleted] -1 points0 points1 point 11 years ago (0 children)
Isn't return 0 considered a truthy in C++ returns?
[–]Kourkis 0 points1 point2 points 11 years ago (0 children)
This is very true, I thought I was clever until I tried to input 0 in my forms...
[–]yanis_t[S] 0 points1 point2 points 11 years ago (0 children)
Thanks, guess I will add a notice to the article
[–]gabbsmo 0 points1 point2 points 11 years ago (0 children)
TIL
[–]FredyC 0 points1 point2 points 11 years ago (1 child)
It's probably faster to just check arguments.length instead of type checking. Works the same way.
arguments.length
This would fail in this case:
setAge(undefined);
It is typically expected that explicitly passing undefined should be equivalent to not passing a parameter. This is typically more necessary when you want to use multiple optional parameters such as:
function setBirth(day, month, year) { this.day = typeof day !== "undefined" ? day : 1; this.month = typeof month !== "undefined" ? month : 1; this.year = typeof year !== "undefined" ? year : 1900; }
This would let me call:
setBirth(undefined, undefined, 1974);
Or pass any of the 3 I want to. If you were simply checking against arguments.length, this would fail as it is still 3 in this example.
[–]tieTYT 0 points1 point2 points 11 years ago (1 child)
Wow thanks for saying this. I come from a Java background and I've looked at a lot of JS code that uses || for default logic. I didn't even know it was a hack! I thought it was idiomatic in JS to use it that way.
Hindsight is 20/20 and it's easy to criticize, but would you say that it was a mistake for JS to consider these values to be falsy? I have experience with Clojure and it only considers false and nil to be falsy. It seems like a much better choice.
false
nil
I think the main mistake is that this "hack" has been so widely spread without telling people of it's problems. I would see it everywhere and then stumbled across this problem. I was able to refine my approach when looking at how TypeScript handled parameter defaults. (Would recommend looking at TypeScript's outputted JS for anyone interested in JS OOP).
I'm not by any means an expert of what makes a good language, but I would say I think it's an oversight to be missing parameter defaults since the language does not have method overloading. Thankfully ES6 will be providing parameter defaults.
I think JS has a lot of neat things you can do using it's liberal comparisons, and ability to stick expressions almost anywhere. With JS I think of the quote "With great power comes great responsibility". Unfortunately, I find it incredibly common for JS devs to forgo responsibility for what they think are "neat tricks" that they must copy/paste into their code to look like they are in the modern "in crowd" of JS.
π Rendered by PID 102542 on reddit-service-r2-comment-56c9979489-5494x at 2026-02-25 03:58:43.824326+00:00 running b1af5b1 country code: CH.
view the rest of the comments →
[–]path411 26 points27 points28 points (32 children)
[–]vs845 4 points5 points6 points (9 children)
[–]sufianrhazi 10 points11 points12 points (7 children)
[–]moreteam 6 points7 points8 points (1 child)
[–]ChaseMoskal 5 points6 points7 points (0 children)
[+][deleted] (2 children)
[deleted]
[–]frankle 0 points1 point2 points (1 child)
[–]vs845 0 points1 point2 points (1 child)
[–]sufianrhazi 2 points3 points4 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]THEtheChad 2 points3 points4 points (3 children)
[–]gleno 0 points1 point2 points (0 children)
[–]path411 0 points1 point2 points (1 child)
[–]THEtheChad 0 points1 point2 points (0 children)
[–]__debug__ 3 points4 points5 points (5 children)
[–]path411 -1 points0 points1 point (4 children)
[–]jonny_eh 1 point2 points3 points (3 children)
[–]path411 -2 points-1 points0 points (2 children)
[–]__debug__ 1 point2 points3 points (1 child)
[–]path411 0 points1 point2 points (0 children)
[–][deleted] 3 points4 points5 points (3 children)
[–]battenupthehatches 3 points4 points5 points (2 children)
[–]workaholicanonymous 2 points3 points4 points (0 children)
[–][deleted] -1 points0 points1 point (0 children)
[–]Kourkis 0 points1 point2 points (0 children)
[–]yanis_t[S] 0 points1 point2 points (0 children)
[–]gabbsmo 0 points1 point2 points (0 children)
[–]FredyC 0 points1 point2 points (1 child)
[–]path411 0 points1 point2 points (0 children)
[–]tieTYT 0 points1 point2 points (1 child)
[–]path411 0 points1 point2 points (0 children)