Is there a null-coalescing (Elvis) operator or safe navigation operator in javascript?
I'll explain by example:
Elvis Operator (?: )
The "Elvis operator" is a shortening of Java's ternary operator. One instance of where this is handy is for returning a 'sensible default' value if an expression resolves to false or null. A simple example might look like this:
def gender = user.male ? "male" : "female" //traditional ternary开发者_如何学运维 operator usage
def displayName = user.name ?: "Anonymous" //more compact Elvis operator
Safe Navigation Operator (?.)
The Safe Navigation operator is used to avoid a NullPointerException. Typically when you have a reference to an object you might need to verify that it is not null before accessing methods or properties of the object. To avoid this, the safe navigation operator will simply return null instead of throwing an exception, like so:
def user = User.find( "admin" ) //this might be null if 'admin' does not exist
def streetName = user?.address?.street //streetName will be null if user or user.address is null - no NPE thrown
You can use the logical 'OR' operator in place of the Elvis operator:
For example displayname = user.name || "Anonymous"
.
But Javascript currently doesn't have the other functionality. I'd recommend looking at CoffeeScript if you want an alternative syntax. It has some shorthand that is similar to what you are looking for.
For example The Existential Operator
zip = lottery.drawWinner?().address?.zipcode
Function shortcuts
()-> // equivalent to function(){}
Sexy function calling
func 'arg1','arg2' // equivalent to func('arg1','arg2')
There is also multiline comments and classes. Obviously you have to compile this to javascript or insert into the page as <script type='text/coffeescript>'
but it adds a lot of functionality :) . Using <script type='text/coffeescript'>
is really only intended for development and not production.
I think the following is equivalent to the safe navigation operator, although a bit longer:
var streetName = user && user.address && user.address.street;
streetName
will then be either the value of user.address.street
or undefined
.
If you want it to default to something else you can combine with the above shortcut or to give:
var streetName = (user && user.address && user.address.street) || "Unknown Street";
2020 Update
JavaScript now has equivalents for both the Elvis Operator and the Safe Navigation Operator.
Safe Property Access
The optional chaining operator (?.
) is currently a stage 4 ECMAScript proposal. You can use it today with Babel.
// `undefined` if either `a` or `b` are `null`/`undefined`. `a.b.c` otherwise.
const myVariable = a?.b?.c;
The logical AND operator (&&
) is the "old", more-verbose way to handle this scenario.
const myVariable = a && a.b && a.b.c;
Providing a Default
The nullish coalescing operator (??
) is currently a stage 4 ECMAScript proposal. You can use it today with Babel. It allows you to set a default value if the left-hand side of the operator is a nullary value (null
/undefined
).
const myVariable = a?.b?.c ?? 'Some other value';
// Evaluates to 'Some other value'
const myVariable2 = null ?? 'Some other value';
// Evaluates to ''
const myVariable3 = '' ?? 'Some other value';
The logical OR operator (||
) is an alternative solution with slightly different behavior. It allows you to set a default value if the left-hand side of the operator is falsy. Note that the result of myVariable3
below differs from myVariable3
above.
const myVariable = a?.b?.c || 'Some other value';
// Evaluates to 'Some other value'
const myVariable2 = null || 'Some other value';
// Evaluates to 'Some other value'
const myVariable3 = '' || 'Some other value';
Javascript's logical OR operator is short-circuiting and can replace your "Elvis" operator:
var displayName = user.name || "Anonymous";
However, to my knowledge there's no equivalent to your ?.
operator.
I've occasionally found the following idiom useful:
a?.b?.c
can be rewritten as:
((a||{}).b||{}).c
This takes advantage of the fact that getting unknown attributes on an object returns undefined, rather than throwing an exception as it does on null
or undefined
, so we replace null and undefined with an empty object before navigating.
i think lodash _.get()
can help here, as in _.get(user, 'name')
, and more complex tasks like _.get(o, 'a[0].b.c', 'default-value')
There is currently a draft spec:
https://github.com/tc39/proposal-optional-chaining
https://tc39.github.io/proposal-optional-chaining/
For now, though, I like to use lodash get(object, path [,defaultValue])
or dlv delve(obj, keypath)
Update (as of Dec 23, 2019):
optional chaining has moved to stage 4
For the former, you can use ||
. The Javascript "logical or" operator, rather than simply returning canned true and false values, follows the rule of returning its left argument if it is true, and otherwise evaluating and returning its right argument. When you're only interested in the truth value it works out the same, but it also means that foo || bar || baz
returns the leftmost one of foo, bar, or baz that contains a true value.
You won't find one that can distinguish false from null, though, and 0 and empty string are false values, so avoid using the value || default
construct where value
can legitimately be 0 or ""
.
精彩评论