0

In JavaScript you can make a function like this:

function Cat(children) {
    this.children = children || 3;
}

What it does is that it creates a Cat object with a children value, if you do not pass the children inside the function like var mimmi = new Cat();, it will be the same as var mimmi = new Cat(undefined);, which means that mimmi will have the default amount of children which is 3.

However, the only problem with this is that if I enter 0, it will be count as false and children will be set to 3, when I actually want it to be set to 0.

What's the most elegant way to make a function like this but still allow for 0's?

I don't really think this is so nice looking though:

function Cat(children) {
    this.children = (typeof this.children == "number") ? children : 3
}
  • it's not nice looking, but it's what's required. – Alnitak Mar 06 '15 at 15:03
  • possible duplicate of [Is there a better way to do optional function parameters in Javascript?](http://stackoverflow.com/questions/148901/is-there-a-better-way-to-do-optional-function-parameters-in-javascript) – JJJ Mar 06 '15 at 15:03
  • @Juhana this is about a specific case - that question is about optional parameters in general. – Benjamin Gruenbaum Mar 06 '15 at 15:05
  • Would `children >= 0 ? children : 3` be any better? Same idea as the second example, but shorter – MDEV Mar 06 '15 at 15:06
  • @BenjaminGruenbaum This specific case falls neatly within the general case. The accepted answer even addresses the 0-case directly. – JJJ Mar 06 '15 at 15:06
  • Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not"! –  Mar 06 '15 at 15:06

4 Answers4

5

Right, there is no elegant way in ES5 to do that, you should never use || for default value with primitives (string, number, boolean, null and undefined) for precisely the reason you thought of.

The code you have with the typeof is almost correct (should check typeof of just children) and is correct:

function Cat(children) {
    this.children = (typeof children === "number") ? children : 3
}

In ES6 you get default parameters which make this a lot nicer:

function Cat(children = 3) {
    this.children = children; // requires a runtime that supports ES6
}

Although the more ES6 way would be to use a class.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • 3
    Cool to see that there is a way to do this with ES6! – Brad Mar 06 '15 at 15:04
  • About the function with ES6, where do you put the `3`? –  Mar 06 '15 at 15:07
  • @Murplyx that was a silly mistake :D I wrote 0 instead of 3 there. Fixed now. – Benjamin Gruenbaum Mar 06 '15 at 15:08
  • @Murplyx if you want to write ES6 code currently transpilation is required through TypeScript or Babel, personally I prefer Babel since it adheres to the standard more closely, doesn't impose new constructs and is easier to use in my experience (just another `script` tag). – Benjamin Gruenbaum Mar 06 '15 at 15:10
  • So bad just that normal browsers like chrome doesn't support it –  Mar 06 '15 at 15:15
  • @Murplyx that's because Chrome are moving JS engine compilers right now (from CrankShaft to TurboFan) so it'll take a bit, once they're done transitioning features will get in very fast. – Benjamin Gruenbaum Mar 06 '15 at 15:17
3

Since it is a numerical value that you want can use isNaN()

function Cat(children) {
    this.children = isNaN(children) ? 3 : children;
}
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • 1
    Really nice case-specific answer! –  Mar 06 '15 at 15:15
  • Note that this has different results from OP's code if you pass `NaN` which is a number. Not that it's a big deal. – Benjamin Gruenbaum Mar 06 '15 at 15:34
  • @BenjaminGruenbaum NaN stands for "Not a Number" so NaN therefore, is not a number simply :D –  Mar 06 '15 at 15:35
  • @Murplyx NaN is a number, `typeof NaN` returns number, it was poorly named but you can easily get it by applying operations to numbers (for example 1/0) - see [here - "Number value"](http://es5.github.io/#x4.3.23). Like I said - really not a big deal. Just a semantic difference. – Benjamin Gruenbaum Mar 06 '15 at 15:39
  • @BenjaminGruenbaum that doesn't make sense , `isNaN( NaN)` returns true – charlietfl Mar 06 '15 at 15:39
  • @charlietfl right, because `isNaN` checks if something, when coerced to a number is `NaN` - when you coerce or convert something that is not a number to a number in JS it might be a valid number or NaN (which is still a number, since you converted it to a number) - it just represents an "invalid" number. – Benjamin Gruenbaum Mar 06 '15 at 15:42
0

I came up with a solution which is great for doing this with multiple functions and variables:

function por(p, d) { // por = parameter or gate
    return ((typeof p === "undefined") ? d : p);
}

where p is the parameter and d is the default value.

In the Cat case, you could use this like this:

function Cat(children) {
    this.children = por(children, 3);
}

With "multiple functions and variables" I mean when you need to do it on a large scale, for example:

function ABC(a, b, c) {
    this.a = por(a, 1);
    this.b = por(b, 2);
    this.c = por(c, 3);
}

rather than:

function ABC(a, b, c) {
    this.a = ((typeof a === "undefined") ? 1 : a);
    this.b = ((typeof b === "undefined") ? 2 : b);
    this.c = ((typeof c === "undefined") ? 3 : c);
}
  • For discussion about this pattern see http://programmers.stackexchange.com/questions/203469/if-my-team-has-low-skill-should-i-lower-the-skill-of-my-code – Benjamin Gruenbaum Mar 06 '15 at 15:31
0

As you have found out, 0 is a boolean value. You should be checking for an undefined value.

Try:

var Cat = function(children) {
 this.children = (children === undefined) ? 3 : children;
};
AJ72
  • 168
  • 1
  • 12