All .filter's callback cares about is the truthy or falsey value returned inside it. Here, it'd be better to return that comparison directly, no conditional operator needed:
Copyconst interestingWords = words.filter(word => word.length > 5);
A construction like
Copyreturn word ? word.length > 5 : null
could make sense if you needed to check a sub-property, but only if the array element existed first, eg:
Copyconst objects = [
null,
{ word: 'foo' },
{ word: 'barbar' },
null
];
const interestingObjects = objects.filter(
obj => obj ? obj.word.length > 5 : null
);
console.log(interestingObjects);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Answer from CertainPerformance on Stack OverflowAll .filter's callback cares about is the truthy or falsey value returned inside it. Here, it'd be better to return that comparison directly, no conditional operator needed:
Copyconst interestingWords = words.filter(word => word.length > 5);
A construction like
Copyreturn word ? word.length > 5 : null
could make sense if you needed to check a sub-property, but only if the array element existed first, eg:
Copyconst objects = [
null,
{ word: 'foo' },
{ word: 'barbar' },
null
];
const interestingObjects = objects.filter(
obj => obj ? obj.word.length > 5 : null
);
console.log(interestingObjects);
Run code snippetEdit code snippet Hide Results Copy to answer Expand
If elements of the array might be null or undefined, you can use the optional chaining operator.
Copyconst interestingWords = words.filter(word => {
return word?.length > 5
})
2020 Answer, It Exists!!!
You can now directly use ?. inline to test for existence. It is called the Optional Chaining Operator, supported by all modern browsers.
If a property exists, it proceeds to the next check, or returns the value. Any failure will immediately short-circuit and return undefined.
const example = {a: ["first", {b:3}, false]}
example?.a // ["first", {b:3}, false]
example?.b // undefined
example?.a?.[0] // "first"
example?.a?.[1]?.a // undefined
example?.a?.[1]?.b // 3
domElement?.parentElement?.children?.[3]?.nextElementSibling
To ensure a default defined value, you can use ??. If you require the first truthy value, you can use ||.
example?.c ?? "c" // "c"
example?.c || "c" // "c"
example?.a?.[2] ?? 2 // false
example?.a?.[2] || 2 // 2
If you do not check a case, the left-side property must exist. If not, it will throw an exception.
example?.First // undefined
example?.First.Second // Uncaught TypeError: Cannot read property 'Second' of undefined
?. Browser Support - 94%, Oct '22
?? Browser Support - 94%
Node Support - v14+
Update 2020
This long-wished feature is now available in JavaScript!
I'll redirect to Gibolt's answer, which covers it well.
Original 2018 answer
There is no "null-safe navigation operator" in Javascript (EcmaScript 5 or 6), like
?.in C#, Angular templates, etc. (also sometimes called Elvis operator, when written?:) , at least yet, unfortunately.You can test for
nulland return some dependent expression in a single line with the ternary operator?:, as already given in other answers :
(use === null to check only for nulls values, and == null to check for null and undefined)
console.log(myVar == null ? myVar.myProp : 'fallBackValue');
in some cases, like yours, when your variable is supposed to hold an
object, you can simply use the fact that any object is truthy whereasnullandundefinedare falsy values :if (myVar) console.log(myVar.myProp) else console.log('fallbackValue')You can test for falsy values by coalescing to boolean with
!!and make this inline :console.log(!!myVar ? myVar.myProp : 'fallbackValue');Be very careful though with this "falsy test", for if your variable is
0,'', orNaN, then it is falsy as well, even though it is not null/undefined.
Empty string is also a falsy value.
If any() returns an empty string, !isMobile.any() ? false : true will return false, but you probably want true.
This means your code is incorrect for this case.
I'd just do something like isMobile.any() !== null.
As per the any() function, you are returning value of the following expression:
(isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS()
|| isMobile.Opera() || isMobile.Windows())
Each of these functions can either return an Array or null as seen in the doc for match
So while evaluating the OR it will evaluate to the first truth value encountered and doesnt evaluate any further as the expression is already fit to be true. So, for example if the browser is android the expression evaluates to ["Android"]. If windows it will be ["Windows"]. If none of these, it will be null. Which makes it clear that any() can only return an Array or null.
isMobileBrowser should be true if it's any of these mobile browsers, which means isMobileBrowser should be true if:
any() evaluates to an Array
OR in other way:
If any() does not evaluate to null
which is:
$scope.isMobileBrowser = isMobile.any() instanceof Array;//looks messy
$scope.isMobileBrowser = (isMobile.any()).constructor === Array;//looks messy
$scope.isMobileBrowser = Array.isArray(isMobile.any());//looks messy
$scope.isMobileBrowser = Object.prototype.toString.call(isMobile.any())
=== "[object Array]";//looks messy
OR the other way:
$scope.isMobileBrowser = isMobile.any() !== null;
$scope.isMobileBrowser = !(isMobile.any() === null);
isMobileBrowser = !(Object.prototype.toString.call(isMobile.any())
=== "[object Null]");//looks messy
So we just discussed different ways to check for null and Array. You have two possible sets of outputs
nullvalue which is alwaysfalse- An
Arraywhich is alwaystrue(You can check this empty array scenario although that doesn't apply here)
So you can simply do the following to convert those to exact boolean without worrying much:
isMobileBrowser = Boolean(isMobile.any()); //to convert value to boolean
isMobileBrowser = !!isMobile.any(); //another way to convert to boolean
//!!["Android"] is true
//!!null is false
@rossipedia explains the !! well in his answer.
For example, I have a game of snake in which each time the snake moves I check if it has eaten an apple, a powerup or itself. I could use multiple if statements, ie:
if(snakeAteSelf) {
callFunction1
}
if(snakeAtePowerUp) {
callFunction2
}
if(snakeAteApple) {
callfunction3
}But instead I'm doing something more similar to
snakeAteSelf ? callFunction1 : null snakeAtePowerup ? callFunction2 : null snakeAteApple ? callFunction3 : null
But the null just stands out as odd looking to me, despite the rest of the code looking more concise.
EDIT: If anyone is interested in critiquing my game of snake you can play it here (press arrow keys to start, you wrap around edges so don't worry about hitting them) and view the code here.
You could expand your condition from just e to (e && e.className). That should prevent script errors resulting from passing in random junk or even non-element nodes.
Better, implement that condition as function hasClassName(e) { return ... } and use hasClassName(e) as your test.
EDIT: Replaced less-than-fully-compatible (typeof e=="object") && ('className' in e) condition, per comments. See also How do I check if an object has a property in JavaScript?
The code as it stands, will work if you pass in a string. However, if you want to be sure that you're only passing in a DOM element (it's better to be strict), you can modify your code to this:
function isNode(o){
return (
typeof Node === "object" ? o instanceof Node :
typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName==="string"
);
}
function isElement(o){
return (
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
typeof o === "object" && o.nodeType === 1 && typeof o.nodeName==="string"
);
}
var changeColorTo = {
grey: function(e) {
isNode(e) || isElement(e) ? (e.className = "grey") : "" ;
},
...
}
For more information on how isNode and isElement work, take a look at this stackoverflow answer. This code will also ensure that you won't try to change the className attribute of a null or undefined variable since the first condition in each of those functions (o instanceof Node and o instanceof HTMLElement) will fail, which ensures that isNode and isElement will return false for null and undefined values.
Let's do some fixing. First, this is how you pass optional (non-boolean) parameters in JS (the Good Waytm):
addFooListeners = function (panelType, handlers) {
handlers = handlers || {};
handlers.show = handlers.show || showFoo;
handlers.hide = handlers.hide || hideFoo;
handlers.commit = handlers.commit || commitFoo;
The above can be rewritten in a neater way using jQuery (not sure what the name of YUI equivalent to extend is):
handlers = $.extend({
show : showFoo,
hide : hideFoo,
commit: commitFoo
}, handlers || {})
Now, using eval for this code is criminal. Say the object ns refers to is module, then you can do this instead of eval:
YAHOO.util.Event.addListener("show" + panelType, "click", handlers.show, module["panel_" + panelType], true);
YAHOO.util.Event.addListener("hide" + panelType, "click", handlers.hide, module["panel_" + panelType], true);
YAHOO.util.Event.addListener("commit" + panelType, "click", handlers.commit, module["panel_" + panelType], true);
Now, as you can see, you are assigning a lot of events in a similar fashion. Did you think of defining an addPanelListener function within your function?
function addPanelListener (event, panelType, handler) {
YAHOO.util.Event.addListener(event + panelType, "click", handler, module["panel_" + panelType], true);
}
addPanelListener("show" , panelType, handlers.show);
addPanelListener("hide" , panelType, handlers.hide);
addPanelListener("commit", panelType, handlers.commit):
Hope it helps.
It looks like you can reduce that ternary a bit by using && like this:
var handlers = {
show: ( overrides != null && overrides.show != null ? overrides.show : showFoo ),
hide: ( overrides != null && overrides.hide != null ? overrides.hide : hideFoo ),
commit: ( overrides != null && overrides.commit != null ? overrides.commit : commitFoo )
}
I'm not too familiar with javascript but does the function parameter have to be checked against null? Like for example, can you further shorten the check by doing something like this?
show: ( overrides && overrides.show ? overrides.show : showFoo ),
hide: ( overrides && overrides.hide ? overrides.hide : hideFoo ),
// ...
First of all, a ternary expression is not a replacement for an if/else construct - it's an equivalent to an if/else construct that returns a value. That is, an if/else clause is code, a ternary expression is an expression, meaning that it returns a value.
This means several things:
- use ternary expressions only when you have a variable on the left side of the
=that is to be assigned the return value - only use ternary expressions when the returned value is to be one of two values (or use nested expressions if that is fitting)
- each part of the expression (after ? and after : ) should return a value without side effects (the expression
x = truereturns true as all expressions return the last value, but it also changes x without x having any effect on the returned value)
In short - the 'correct' use of a ternary expression is
var resultofexpression = conditionasboolean ? truepart: falsepart;
Instead of your example condition ? x=true : null ;, where you use a ternary expression to set the value of x, you can use this:
condition && (x = true);
This is still an expression and might therefore not pass validation, so an even better approach would be
void(condition && x = true);
The last one will pass validation.
But then again, if the expected value is a boolean, just use the result of the condition expression itself
var x = (condition); // var x = (foo == "bar");
UPDATE
In relation to your sample, this is probably more appropriate:
defaults.slideshowWidth = defaults.slideshowWidth || obj.find('img').width()+'px';
No, it needs three operands. That's why they're called ternary operators.
However, for what you have as your example, you can do this:
if(condition) x = true;
Although it's safer to have braces if you need to add more than one statement in the future:
if(condition) { x = true; }
Edit: Now that you mention the actual code in which your question applies to:
if(!defaults.slideshowWidth)
{ defaults.slideshowWidth = obj.find('img').width()+'px'; }