while b and c throw ReferenceError when abc is undefined
So abc isn't just undefined, it's undeclared. There's a big difference there.
If you need to handle abc being undeclared, the only safe way to do that (without try/catch) is with typeof:
typeof abc === "undefined"
That will be true, without error, if abc is an undeclared identifier. It will also be true if abc is declared and contains the value undefined.
What is the best and short way to check if
abcis undefined before accessing its properties as well as assign blank object{}if undefined?
Probably using var to ensure it's declared:
var abc = abc || {};
Duplicate var declarations are not errors (duplicate let declarations are). So with the above, if abc is undeclared, it gets declared with the initial value undefined and we assign it {}. If it's declared, we replace its value with {} if it's falsy. But, if it may or may not be declared with let or const, then the above will throw an error as well.
So to handle the case where it may or may not be declared with let or const, we need a different variable entirely:
let ourabc = typeof abc === "undefined" || !abc ? {} : abc;
That sets ourabc to {} if abc is undeclared or if it contains a falsy value. Since all non-null object references are truthy, and you've said you want to access object properties, that's probably the shortest way.
while b and c throw ReferenceError when abc is undefined
So abc isn't just undefined, it's undeclared. There's a big difference there.
If you need to handle abc being undeclared, the only safe way to do that (without try/catch) is with typeof:
typeof abc === "undefined"
That will be true, without error, if abc is an undeclared identifier. It will also be true if abc is declared and contains the value undefined.
What is the best and short way to check if
abcis undefined before accessing its properties as well as assign blank object{}if undefined?
Probably using var to ensure it's declared:
var abc = abc || {};
Duplicate var declarations are not errors (duplicate let declarations are). So with the above, if abc is undeclared, it gets declared with the initial value undefined and we assign it {}. If it's declared, we replace its value with {} if it's falsy. But, if it may or may not be declared with let or const, then the above will throw an error as well.
So to handle the case where it may or may not be declared with let or const, we need a different variable entirely:
let ourabc = typeof abc === "undefined" || !abc ? {} : abc;
That sets ourabc to {} if abc is undeclared or if it contains a falsy value. Since all non-null object references are truthy, and you've said you want to access object properties, that's probably the shortest way.
state = (typeof state !== "undefined") ? state : '';
This way you can check undefined variable in a ternary operator.
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.
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.
There is a difference between this:
var ex1 = {foo: undefined};
and this:
var ex2 = {};
Therefore, here's how I would do it:
var args = {
bing: 'bing',
boom: 'boom'
};
if (typeof myVar !== 'undefined') {
args.bang = myVar;
}
someFunc(args, 'yay');
i would do something like
var config = {
bing: "bing",
boom: "boom"
};
if (typeof myVar !== 'undefined') config.bang = myVar;
someFunc(config, 'yay');
you have to be careful of javascript truthiness and falsiness. The if statement in my example only puts bang on config if myVar is defined, but it works if myVar is defined as false.
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 ),
// ...
You're missing the return in your isBreadWinner function.
let isBreadwinner = function() {
return (user.salary) ? true : false;
};
If you want to skip using a return then you might want to use an ES6 arrow function which has implicit returns if everything is declared on one line without a block, {}.
let isBreadwinner = () => (user.salary) ? true : false;
you may write the function like this
let isBreadwinner = () => (user.salary) ? true : false;
or just add return to your function
In general, keep it simple.
To check for undefined, use:
foo === undefined
foo !== undefined
To check for null, use:
foo === null
foo !== null
To check for either at the same time, use:
foo == null
foo != null
And in any case, store your .prop() to a variable to keep it clean. But in your case, if it equals "_blank", then you know it isn't null or undefined, so:
var targ = jQuery(this).prop("target").toLowerCase();
var c = targ === "_blank" ? 1 : 0;
Or you could make it even shorter by coercing the boolean to a number:
var targ = jQuery(this).prop("target").toLowerCase();
var c = +(targ === "_blank");
These last two solutions are safe because .prop() will always return a string.
Both
nullandundefinedare "falsy" values, thus they can be checked like they were boolean values. Thus, there's no sense comparing tonullandundefinedexcept for certain situations where you need to know if they are such values.when comparing, it's best to use strict comparison (like
===,!==and so on)the
&&in a condition does not evaluate the following condition if the one preceeding it is "falsy".You don't even need jQuery since
thisis your DOM object (presumably an<a>) and you are trying to get thetargetproperty:
In the end:
var c = (this.target && this.target.toLowerCase() === "_blank") ? 1 : 0;
What you have will work if you finish the ternary expression:
return typeof this.scores != 'undefined' ? this.scores.filter() : null;
You can replace null with whatever value you want to return instead.
You could return an undefined or the value of the function call by using a logical AND && instead of a conditional (ternary) operator ?: without an else part (which is not possible).
return this.scores && this.scores.filter();
var startingNumber = startingNumber || 1;
Something like that what you're looking for, where it defaults if undefined?
var foo = bar || 1; // 1
var bar = 2;
foo = bar || 1; // 2
By the way, this works for a lot of scenarios, including objects:
var foo = bar || {}; // secure an object is assigned when bar is absent
|| will return the first truthy value it encounters, and can therefore be used as a coalescing operator, similar to C#'s ??
startingNum = startingNum || 1;