1

In JavaScript I often use the || operator to get the value of some property - or a default value. For instance:

var dens = mapping.defaultElementNamespaceURI||mapping.dens||'';

If mapping has defaultElementNamespaceURI, it will be used, otherwise look for dens or use an empty string by default.

However if my property is boolean, it does not work:

var dom = mapping.allowDom || mapping.dom || true;

Returns true even if mapping.dom is false.

I wonder, what would be the best (laconic but still readable) syntax for defaulting boolean properties? Defaulting in a sense that if the property is defined, use its value otherwise some provided default value. I can write a function for this, sure, but maybe there's someting as elegant as a || b || c?

Code sample:

var a = {};
$('#result').text(a.boo||a.b||true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="result"></pre>


Update

Seems like there's no "syntactically sweet" way to do this, so I've resorted to writing a function:

var defaultValue = function()
{
    var args = arguments;
    if (args.length === 0)
    {
        return undefined;
    }
    else
    {
        var defaultValue = args[args.length - 1];
        var typeOfDefaultValue = typeof defaultValue;
        for (var index = 0; index < args.length - 1; index++)
        {
            var candidateValue = args[index];
            if (typeof candidateValue === typeOfDefaultValue)
            {
                return candidateValue;
            }
        }
        return defaultValue;

    }
}

Considers the last argument to be the default value. Returns the first argument which has the same type as the default value.

11
  • You'd have to explicitly test the value. If you are working with config objects, you can also write a simple merge function that only copies the property if it doesn't exist. Commented Apr 2, 2015 at 21:59
  • 1
    You basically are stuck with doing typeof tests or === tests (in a way that works, as opposed to my deleted answer :) Commented Apr 2, 2015 at 22:00
  • yep! misunderstood, and deleted my comment :] Commented Apr 2, 2015 at 22:01
  • @Patrick I was also thinking: huh, your code is doing exactly what it is intended to do, but with Pointy's comment I see now :) Commented Apr 2, 2015 at 22:02
  • Does this get you what you want? var dom = mapping.allowDom ? mapping.allowDom : mapping.dom ? mapping.dom : true; ? Commented Apr 2, 2015 at 22:04

6 Answers 6

3

The closest thing to elegant you'll find is:

var dom = mapping.allowDom ? mapping.allowDom : mapping.dom ? mapping.dom : true;

As pointed out, this is merely a presence check. You could do either of these to accept false values:

var dom = mapping.allowDom != null ? mapping.allowDom : mapping.dom != null ? mapping.dom : true;

var dom = 'allowDom' in mapping ? mapping.allowDom : 'dom' in mapping ? mapping.dom : true;

Update for completeness: The function in your update is ideal if you have a variable list of values to compare against. But, if the only things we're comparing are the 2 mentioned (and we were in control of setting/verifying mapping.thing) my code would look like the following. (I also don't know how you're using dom later on.)

var dom = mapping.allowDom || mapping.dom;
dom = dom === undefined ? true : dom;

Anything more than 2 elements and I would probably opt for your method.

Sign up to request clarification or add additional context in comments.

7 Comments

Is the OP sure this is what he wants. I tried it here, jsfiddle.net/myra7x2m and I got true when the values had false in them.
This will fail on false values as well, as the ternary will continue if the value is false, not just when it's undefined etc.
Valid points. My original comment asked if this was the desired outcome. A sample modification could be this: jsfiddle.net/myra7x2m/1
I like the != null it's better than my answer as it should cover undefined and null.
@John Yes. I tested the compare to both. As long as you don't do the strict !== check this should solve both. Just tell jshint to be quiet about it. =)
|
2
a.x || b

will return the value of b if a.x is "falsey" -- undefined, empty string, 0, a few other values.

If you need to display something unless the field is in an object, even if the field's value is falsey, you have to say so explicitly.

'x' in a ? a.x : b

If you explicitly set a.x to undefined, that expression will return 'undefined', not b.

Comments

1

It's a lot longer than the accepted answer, but it should give you exactly what you want from what I understand.

var mapping = {dom: false};
var dom = typeof mapping.allowDom !== "undefined" ? mapping.allowDom : typeof mapping.dom !== "undefined" ? mapping.dom : true;
$('#result').append("" + dom);

More tests on this fiddle.

http://jsfiddle.net/myra7x2m/

4 Comments

Is there a benefit to using typeof over a != null or in comparison?
@Tony != null is better if he wants it to be true when it's null or undefined which I assume is what he wants, but he may only want it when it is undefined I am unsure. I did post a comment on your answer as soon as I saw it updated.
@Tony Oh and as for the in comparison if he wanted to set a certain thing to be undefined he could whereas with in you would have to delete the element instead to have the same effect so not much difference there just different preference. So the only problem with in is if the element is literally undefined it will return undefined.
Looks like typeof would be the preferred route based on this answer.
1

Another nice form of implementation is via function and switch without control expression what makes it to a nicer if/else block:

dom = (function() {
    switch (false) {
      case mapping.allowDom == null:
        return mapping.allowDom;
      case mapping.dom == null:
        return mapping.dom;
      default:
        return true;
    }
})();

You can test this here

http://jsfiddle.net/w3jtsk5u/

If you are wondering, why i am comparing for == null and not != null and it still is working, is that i used switch(false) so the value compared to is false which negates the expression.

for compact friends, of course you could write:

dom = (function(){switch(false){
  case mapping.allowDom == null: return mapping.allowDom;
  case mapping.dom == null:      return mapping.dom;
  default:                       return true;
}})();

still readable :)

1 Comment

I like the idea of a function not everything can or I guess I should say should be put on one line. Yeah it's elegant, but sometimes you give up readability and simplicity with that approach.
0

When it comes to options that are booleans testing for null is the way to go:

var dom;
if (mapping.allowDom != null) {
  dom = mapping.allowDom;
} else if (mapping.dom != null) {
  dom = mapping.dom;
} else {
  dom = true;
}

I would wrap the above in a function or a Maybe monad. Note this is the only use case I use the == or != operators any other comparison is always the === or !== operators. Because a == null will test for null or undefined.

2 Comments

Not quite sure why you compare boolean or potentially missing properties with null via the != operator.
You could also compare with mapping.allowDom !== false but I found the != null more expressive to me. And it is also the same output you get from CoffeeScript's default arguments syntax.
0

The OR operator will return the 1st 'truthy' value, if that value is evaluated to false it will check the next until the last.

Therefore it's only possible to have false or 'falsey' value as a default as the last in the sequence.

3 Comments

I am somewhat aware of how it does not work and ask how it does. :)
@lexicore If you are aware of how it does not work then why are you trying to make it work like it does not work if you are aware this?
I'm just pointing out that your answer does not answer my question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.