276

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
11
  • 11
    The 'Elvis Operator' exists in C# -- but it's called the null coalescing operator (much less exciting) :-)
    – Cameron
    Commented Jul 7, 2011 at 16:34
  • If you want an alternative syntax you can take a look of cofeescript
    – Lime
    Commented Jul 7, 2011 at 16:40
  • 5
    This question is sort of a mess... it is mixing up 3 different operators ? : (ternery operator, spelled out in the question, possibly a typo), ?? (null coalescing, which does exist in JavaScript) and ?. (Elvis) which does NOT exist in JavaScript. The answers do not clarify this distinction very well.
    – JoelFan
    Commented Mar 10, 2015 at 1:40
  • 3
    @JoelFan can you provide a link to documentation regarding proper null-coalescence (??) in javascript? Everything I'm finding so far suggests that JS only has "falsey" coalescing (using ||). Commented Jun 14, 2016 at 15:49
  • 1
    Well, I didn't mean to say that JS literally had ?? but that it had null-coalesce... but even there I was kind of wrong. That being said, I have seen a LOT of JS code that uses || as a null coalesce, despite the falsey pitfalls
    – JoelFan
    Commented Jun 16, 2016 at 20:50

22 Answers 22

173

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.

8
  • 19
    logical or is not quite the thing needed in most cases, as you may want it to pick the right operand only if the left is undefined but not when it is defined and falsy. Commented Aug 7, 2014 at 9:06
  • 2
    The CoffeeScript home page uses <script type="text/coffeescript">. Commented Aug 9, 2016 at 22:09
  • 30
    While this answers the question it is almost entirely about coffeescript rather than javascript, and is more than half about describing coffeescript benefits unrelated to the OP. I'd suggest boiling it down to just what's relevant to the question, as wonderful as coffeescript's other benefits are. Commented Oct 4, 2016 at 17:25
  • 4
    Am I going bananas? Surely the objection of user2451227 (currently with 4 votes) is invalid because the ternary's middle operand (i.e. right operand with the Elvis operator) would equally not be picked if the expression/left operand is defined and falsy. In both cases you then have to go x === undefined. Commented Jan 20, 2018 at 17:56
  • 5
    Please consider updating this to mention the optional chaining operator, ?.,. Browser support isn't at the point where I'd use it for general code, but it's heading in that direction. In addition, there's now the nullish coalescing operator (??), with a similar status.
    – Makyen
    Commented Aug 2, 2020 at 16:13
147

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';
4
  • 7
    This answer needs more upvotes. Nullish Coalescing Operator is now in stage 4.
    – Yerke
    Commented Jun 8, 2020 at 8:15
  • 3
    a && a.b && a.c should be a && a.b && a.b.c. I can't edit that in myself because it's not a big enough change for SO to accept and I don't want to do the "change inconsequential things to make it to 6 characters" thing.
    – Emily
    Commented Aug 20, 2020 at 3:43
  • You could add the way to do this with the [] syntax - from developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… , all of these are possible: obj.val?.prop obj.val?.[expr] obj.arr?.[index] obj.func?.(args) Commented Nov 19, 2020 at 7:01
  • String I tried this in the developer tools and one would have expected the result for "const result = a?.b?.c ?? 'Some other value';" to be "Some other value" since I haven't defined "a" but it just throws an "Uncaught ReferenceError: a is not defined". "Is not defined" = undefined right?
    – Jacques
    Commented Jul 20, 2022 at 13:38
142

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";
2
  • 8
    plus one for great example of both null propagation and null coalescence!
    – Jay Wick
    Commented Feb 24, 2016 at 5:18
  • 4
    this works except that you won't know if you get null or undefined out of it Commented Aug 12, 2018 at 4:12
90

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.

2
  • 17
    +1, I forgot || could be used that way. Be aware that this will coalesce not only when the expression is null, but also when it's undefined, false, 0, or the empty string.
    – Cameron
    Commented Jul 7, 2011 at 16:41
  • @Cameron, indeed, but that's mentioned in the question and seems to be the questioner's intent. "" or 0 might be unexpected, though :) Commented Jul 7, 2011 at 16:42
87

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.

5
  • 15
    Well, it's hard to read but it's better than that verbose && method. +1.
    – shriek
    Commented Sep 15, 2016 at 21:06
  • 1
    That's the only real safe operator in javascript actually. The logical 'OR' operator that is mentioned above is something else. Commented Jun 21, 2017 at 13:55
  • @Filippos can you give an example of different behavior in logical OR vs && method ? I can't think of a difference Commented Jul 4, 2017 at 18:37
  • It also allows navigating an anonymous value without assigning it to a variable first. Commented Dec 1, 2017 at 13:59
  • 1
    Love it! Really useful if you want to get the property of an object after an array.find() operation that might not return any results
    – Shiraz
    Commented Apr 30, 2019 at 14:34
25

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')

1
  • 8
    My main issue with this method is the fact that since the name of the properties are string, you can't use refactoring functionalities of your IDE with a 100% trust anymore
    – RPDeshaies
    Commented Oct 15, 2018 at 23:04
23

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

2
  • 1
    Lodash make programming in javascript more palatable
    – geckos
    Commented Mar 31, 2019 at 17:57
  • 5
    optional chaining just recently moved to stage 4, so we'll be seeing it in ES2020 Commented Dec 5, 2019 at 12:28
13

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 "".

1
  • 4
    Good job noting that this can result in unexpected behavior when the left operand is a non-null falsey value.
    – Shog9
    Commented Jul 7, 2011 at 16:38
12

Yes, there is! 🍾

Optional chaining is in stage 4 and this enables you to use the user?.address?.street formula.

If you can't wait the release, install @babel/plugin-proposal-optional-chaining and you can use it. Here are my settings which works for me, or just read Nimmo's article.

// package.json

{
  "name": "optional-chaining-test",
  "version": "1.0.0",
  "main": "index.js",
  "devDependencies": {
    "@babel/plugin-proposal-optional-chaining": "7.2.0",
    "@babel/core": "7.2.0",
    "@babel/preset-env": "^7.5.5"
  }
  ...
}
// .babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "debug": true
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-proposal-optional-chaining"
  ]
}
// index.js

console.log(user?.address?.street);  // it works
5
  • 4
    He asked if there was one, not whether you could add one. I think this isnt super useful considering its not what was asked.
    – DeanMWake
    Commented Aug 29, 2019 at 13:22
  • 2
    It reached stage 3 of the ECMAScript standardization process. es2020 🚀 -- babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
    – wedi
    Commented Sep 18, 2019 at 8:54
  • I think this answer is misleading as is. Commented Oct 11, 2019 at 12:13
  • 1
    This answer isn't quite correct! Optional chaining is still in stage 3 and ES2020 hasn't been released or even finalised yet. At least you mentioned how one can use it without having to wait for it to be released. Commented Nov 28, 2019 at 11:41
  • @gazdagergo No problem :). Commented Nov 29, 2019 at 11:12
6

Here's a simple elvis operator equivalent:

function elvis(object, path) {
    return path ? path.split('.').reduce(function (nestedObject, key) {
        return nestedObject && nestedObject[key];
    }, object) : object;
}

> var o = { a: { b: 2 }, c: 3 };
> elvis(o)

{ a: { b: 2 }, c: 3 }

> elvis(o, 'a');

{ b: 2 }

> elvis(o, 'a.b');

2

> elvis(o, 'x');

undefined
5

You can achieve roughly the same effect by saying:

var displayName = user.name || "Anonymous";
5

UPDATE SEP 2019

Yes, JS now supports this. Optional chaining is coming soon to v8 read more

1
  • Not quite the same. OP is on about null coalescing, but nice answer nonetheless. Commented Nov 28, 2019 at 11:37
3

This is more commonly known as a null-coalescing operator. Javascript does not have one.

3
  • 3
    true in the strict sense, but as other answers have noted JavaScript's logical OR operator can behave as sort of a false -coalescing operator, allowing you to achieve the same brevity in many situations.
    – Shog9
    Commented Jul 7, 2011 at 16:40
  • 1
    This is not a null-coalescing operator. Null-coalescing only works on a single value, not on a chain of property access/function invocations. You can already do null-coalescing with the logical OR operator in JavaScript.
    – user19302
    Commented Nov 18, 2016 at 21:52
  • No, you can do false-coalescing with the logical OR in JavaScript.
    – andresp
    Commented May 15, 2017 at 13:45
2

I have a solution for that, tailor it to your own needs, an excerpt from one of my libs:

    elvisStructureSeparator: '.',

    // An Elvis operator replacement. See:
    // http://coffeescript.org/ --> The Existential Operator
    // http://fantom.org/doc/docLang/Expressions.html#safeInvoke
    //
    // The fn parameter has a SPECIAL SYNTAX. E.g.
    // some.structure['with a selector like this'].value transforms to
    // 'some.structure.with a selector like this.value' as an fn parameter.
    //
    // Configurable with tulebox.elvisStructureSeparator.
    //
    // Usage examples: 
    // tulebox.elvis(scope, 'arbitrary.path.to.a.function', fnParamA, fnParamB, fnParamC);
    // tulebox.elvis(this, 'currentNode.favicon.filename');
    elvis: function (scope, fn) {
        tulebox.dbg('tulebox.elvis(' + scope + ', ' + fn + ', args...)');

        var implicitMsg = '....implicit value: undefined ';

        if (arguments.length < 2) {
            tulebox.dbg(implicitMsg + '(1)');
            return undefined;
        }

        // prepare args
        var args = [].slice.call(arguments, 2);
        if (scope === null || fn === null || scope === undefined || fn === undefined 
            || typeof fn !== 'string') {
            tulebox.dbg(implicitMsg + '(2)');
            return undefined;   
        }

        // check levels
        var levels = fn.split(tulebox.elvisStructureSeparator);
        if (levels.length < 1) {
            tulebox.dbg(implicitMsg + '(3)');
            return undefined;
        }

        var lastLevel = scope;

        for (var i = 0; i < levels.length; i++) {
            if (lastLevel[levels[i]] === undefined) {
                tulebox.dbg(implicitMsg + '(4)');
                return undefined;
            }
            lastLevel = lastLevel[levels[i]];
        }

        // real return value
        if (typeof lastLevel === 'function') {
            var ret = lastLevel.apply(scope, args);
            tulebox.dbg('....function value: ' + ret);
            return ret;
        } else {
            tulebox.dbg('....direct value: ' + lastLevel);
            return lastLevel;
        }
    },

works like a charm. Enjoy the less pain!

2
  • Looks promising, can you submit please the full source? do you have it anywhere public? (e.g. GitHub)
    – Eran Medan
    Commented Mar 27, 2012 at 2:50
  • 1
    I'll create a small excerpt from the code I use it in and will post it on GitHub in a week or so.
    – balazstth
    Commented Apr 11, 2012 at 21:40
2

You could roll your own:

function resolve(objectToGetValueFrom, stringOfDotSeparatedParameters) {
    var returnObject = objectToGetValueFrom,
        parameters = stringOfDotSeparatedParameters.split('.'),
        i,
        parameter;

    for (i = 0; i < parameters.length; i++) {
        parameter = parameters[i];

        returnObject = returnObject[parameter];

        if (returnObject === undefined) {
            break;
        }
    }
    return returnObject;
};

And use it like this:

var result = resolve(obj, 'a.b.c.d'); 

* result is undefined if any one of a, b, c or d is undefined.

1

I read this article (https://www.beyondjava.net/elvis-operator-aka-safe-navigation-javascript-typescript) and modified the solution using Proxies.

function safe(obj) {
    return new Proxy(obj, {
        get: function(target, name) {
            const result = target[name];
            if (!!result) {
                return (result instanceof Object)? safe(result) : result;
            }
            return safe.nullObj;
        },
    });
}

safe.nullObj = safe({});
safe.safeGet= function(obj, expression) {
    let safeObj = safe(obj);
    let safeResult = expression(safeObj);

    if (safeResult === safe.nullObj) {
        return undefined;
    }
    return safeResult;
}

You call it like this:

safe.safeGet(example, (x) => x.foo.woo)

The result will be undefined for an expression that encounters null or undefined along its path. You could go wild and modify the Object prototype!

Object.prototype.getSafe = function (expression) {
    return safe.safeGet(this, expression);
};

example.getSafe((x) => x.foo.woo);
1

Jumping in very late, there's a proposal[1] for optional chaining currently at stage 2, with a babel plugin[2] available. It's not currently in any browser I am aware of.

  1. https://github.com/tc39/proposal-optional-chaining
  2. https://www.npmjs.com/package/@babel/plugin-proposal-optional-chaining
1

This was a problem for me for a long time. I had to come up with a solution that can be easily migrated once we get Elvis operator or something.

This is what I use; works for both arrays and objects

put this in tools.js file or something

// this will create the object/array if null
Object.prototype.__ = function (prop) {
    if (this[prop] === undefined)
        this[prop] = typeof prop == 'number' ? [] : {}
    return this[prop]
};

// this will just check if object/array is null
Object.prototype._ = function (prop) {
    return this[prop] === undefined ? {} : this[prop]
};

usage example:

let student = {
    classes: [
        'math',
        'whatev'
    ],
    scores: {
        math: 9,
        whatev: 20
    },
    loans: [
        200,
        { 'hey': 'sup' },
        500,
        300,
        8000,
        3000000
    ]
}

// use one underscore to test

console.log(student._('classes')._(0)) // math
console.log(student._('classes')._(3)) // {}
console.log(student._('sports')._(3)._('injuries')) // {}
console.log(student._('scores')._('whatev')) // 20
console.log(student._('blabla')._('whatev')) // {}
console.log(student._('loans')._(2)) // 500 
console.log(student._('loans')._(1)._('hey')) // sup
console.log(student._('loans')._(6)._('hey')) // {} 

// use two underscores to create if null

student.__('loans').__(6)['test'] = 'whatev'

console.log(student.__('loans').__(6).__('test')) // whatev

well I know it makes the code a bit unreadable but it's a simple one liner solution and works great. I hope it helps someone :)

1

?? would work in js which is equivalent to ?: in kotlin

0

This was an interesting solution for the safe navigation operator using some mixin..

http://jsfiddle.net/avernet/npcmv/

  // Assume you have the following data structure
  var companies = {
      orbeon: {
          cfo: "Erik",
          cto: "Alex"
      }
  };

  // Extend Underscore.js
  _.mixin({ 
      // Safe navigation
      attr: function(obj, name) { return obj == null ? obj : obj[name]; },
      // So we can chain console.log
      log: function(obj) { console.log(obj); }
  });

  // Shortcut, 'cause I'm lazy
  var C = _(companies).chain();

  // Simple case: returns Erik
  C.attr("orbeon").attr("cfo").log();
  // Simple case too, no CEO in Orbeon, returns undefined
  C.attr("orbeon").attr("ceo").log();
  // IBM unknown, but doesn't lead to an error, returns undefined
  C.attr("ibm").attr("ceo").log();
0

I created a package that makes this a lot easier to use.

NPM jsdig Github jsdig

You can handle simple things like and object:

const world = {
  locations: {
    europe: 'Munich',
    usa: 'Indianapolis'
  }
};

world.dig('locations', 'usa');
// => 'Indianapolis'

world.dig('locations', 'asia', 'japan');
// => 'null'

or a little more complicated:

const germany = () => 'germany';
const world = [0, 1, { location: { europe: germany } }, 3];
world.dig(2, 'location', 'europe') === germany;
world.dig(2, 'location', 'europe')() === 'germany';
-8

Personally i use

function e(e,expr){try{return eval(expr);}catch(e){return null;}};

and for example safe get:

var a = e(obj,'e.x.y.z.searchedField');
2

Not the answer you're looking for? Browse other questions tagged or ask your own question.