Reputation: 43651
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.
Upvotes: 1
Views: 1550
Reputation: 2483
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.
Upvotes: 3
Reputation: 44376
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.
Upvotes: 2
Reputation: 3160
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
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 :)
Upvotes: 1
Reputation: 7329
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.
Upvotes: 1
Reputation: 344
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.
Upvotes: 0
Reputation: 10064
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.
Upvotes: 0