Related
I know that I can test for a JavaScript variable and then define it if it is undefined, but is there not some way of saying
var setVariable = localStorage.getItem('value') || 0;
seems like a much clearer way, and I'm pretty sure I've seen this in other languages.
Yes, it can do that, but strictly speaking that will assign the default value if the retrieved value is falsey, as opposed to truly undefined. It would therefore not only match undefined but also null, false, 0, NaN, "" (but not "0").
If you want to set to default only if the variable is strictly undefined then the safest way is to write:
var x = (typeof x === 'undefined') ? your_default_value : x;
On newer browsers it's actually safe to write:
var x = (x === undefined) ? your_default_value : x;
but be aware that it is possible to subvert this on older browsers where it was permitted to declare a variable named undefined that has a defined value, causing the test to fail.
Logical nullish assignment, ES2020+ solution
New operators are currently being added to the browsers, ??=, ||=, and &&=. This post will focus on ??=.
This checks if left side is undefined or null, short-circuiting if already defined. If not, the right-side is assigned to the left-side variable.
Comparing Methods
// Using ??=
name ??= "Dave"
// Previously, ES2020
name = name ?? "Dave"
// or
if (typeof name === "undefined" || name === null) {
name = true
}
// Before that (not equivalent, but commonly used)
name = name || "Dave" // Now: name ||= "Dave"
Basic Examples
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array Examples
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
??= Browser Support Oct 2022 - 93%
??= Mozilla Documentation
||= Mozilla Documentation
&&= Mozilla Documentation
The 2018 ES6 answer is:
return Object.is(x, undefined) ? y : x;
If variable x is undefined, return variable y... otherwise if variable x is defined, return variable x.
ES2020 Answer
With the Nullish Coalescing Operator, you can set a default value if value is null or undefined.
const setVariable = localStorage.getItem('value') ?? 0;
However, you should be aware that the nullish coalescing operator does not return the default value for other types of falsy value such as 0 and ''.
However, do take note of the browser support. You may need to use a JavaScript compiler like Babel to convert it into something more backward compatible. If you are using Node.js, it has been supported since version 14.
I needed to "set a variable if undefined" in several places. I created a function using #Alnitak answer. Hopefully it helps someone.
function setDefaultVal(value, defaultValue){
return (value === undefined) ? defaultValue : value;
}
Usage:
hasPoints = setDefaultVal(this.hasPoints, true);
It seems more logical to check typeof instead of undefined? I assume you expect a number as you set the var to 0 when undefined:
var getVariable = localStorage.getItem('value');
var setVariable = (typeof getVariable == 'number') ? getVariable : 0;
In this case if getVariable is not a number (string, object, whatever), setVariable is set to 0
In our days you actually can do your approach with JS:
// Your variable is null
// or '', 0, false, undefined
let x = null;
// Set default value
x = x || 'default value';
console.log(x); // default value
So your example WILL work:
const setVariable = localStorage.getItem('value') || 0;
You can use any of below ways.
let x;
let y = 4;
x || (x = y)
in ES12 or after
let x;
let y = 4;
x ||= y;
If you're a FP (functional programming) fan, Ramda has a neat helper function for this called defaultTo :
usage:
const result = defaultTo(30)(value)
It's more useful when dealing with undefined boolean values:
const result2 = defaultTo(false)(dashboard.someValue)
var setVariable = (typeof localStorage.getItem('value') !== 'undefined' && localStorage.getItem('value')) || 0;
Ran into this scenario today as well where I didn't want zero to be overwritten for several values. We have a file with some common utility methods for scenarios like this. Here's what I added to handle the scenario and be flexible.
function getIfNotSet(value, newValue, overwriteNull, overwriteZero) {
if (typeof (value) === 'undefined') {
return newValue;
} else if (value === null && overwriteNull === true) {
return newValue;
} else if (value === 0 && overwriteZero === true) {
return newValue;
} else {
return value;
}
}
It can then be called with the last two parameters being optional if I want to only set for undefined values or also overwrite null or 0 values. Here's an example of a call to it that will set the ID to -1 if the ID is undefined or null, but wont overwrite a 0 value.
data.ID = Util.getIfNotSet(data.ID, -1, true);
Works even if the default value is a boolean value:
var setVariable = ( (b = 0) => b )( localStorage.getItem('value') );
It seems to me, that for current javascript implementations,
var [result='default']=[possiblyUndefinedValue]
is a nice way to do this (using object deconstruction).
How do I check if a particular key exists in a JavaScript object or array?
If a key doesn't exist, and I try to access it, will it return false? Or throw an error?
Checking for undefined-ness is not an accurate way of testing whether a key exists. What if the key exists but the value is actually undefined?
var obj = { key: undefined };
console.log(obj["key"] !== undefined); // false, but the key exists!
You should instead use the in operator:
var obj = { key: undefined };
console.log("key" in obj); // true, regardless of the actual value
If you want to check if a key doesn't exist, remember to use parenthesis:
var obj = { not_key: undefined };
console.log(!("key" in obj)); // true if "key" doesn't exist in object
console.log(!"key" in obj); // Do not do this! It is equivalent to "false in obj"
Or, if you want to particularly test for properties of the object instance (and not inherited properties), use hasOwnProperty:
var obj = { key: undefined };
console.log(obj.hasOwnProperty("key")); // true
For performance comparison between the methods that are in, hasOwnProperty and key is undefined, see this benchmark:
Quick Answer
How do I check if a particular key exists in a JavaScript object or array?
If a key doesn't exist and I try to access it, will it return false? Or throw an error?
Accessing directly a missing property using (associative) array style or object style will return an undefined constant.
The slow and reliable in operator and hasOwnProperty method
As people have already mentioned here, you could have an object with a property associated with an "undefined" constant.
var bizzareObj = {valid_key: undefined};
In that case, you will have to use hasOwnProperty or in operator to know if the key is really there. But, but at what price?
so, I tell you...
in operator and hasOwnProperty are "methods" that use the Property Descriptor mechanism in Javascript (similar to Java reflection in the Java language).
http://www.ecma-international.org/ecma-262/5.1/#sec-8.10
The Property Descriptor type is used to explain the manipulation and reification of named property attributes. Values of the Property Descriptor type are records composed of named fields where each field’s name is an attribute name and its value is a corresponding attribute value as specified in 8.6.1. In addition, any field may be present or absent.
On the other hand, calling an object method or key will use Javascript [[Get]] mechanism. That is a far way faster!
Benchmark
https://jsben.ch/HaHQt
.
Using in operator
var result = "Impression" in array;
The result was
12,931,832 ±0.21% ops/sec 92% slower
Using hasOwnProperty
var result = array.hasOwnProperty("Impression")
The result was
16,021,758 ±0.45% ops/sec 91% slower
Accessing elements directly (brackets style)
var result = array["Impression"] === undefined
The result was
168,270,439 ±0.13 ops/sec 0.02% slower
Accessing elements directly (object style)
var result = array.Impression === undefined;
The result was
168,303,172 ±0.20% fastest
EDIT: What is the reason to assign to a property the undefined value?
That question puzzles me. In Javascript, there are at least two references for absent objects to avoid problems like this: null and undefined.
null is the primitive value that represents the intentional absence of any object value, or in short terms, the confirmed lack of value. On the other hand, undefined is an unknown value (not defined). If there is a property that will be used later with a proper value consider use null reference instead of undefined because in the initial moment the property is confirmed to lack value.
Compare:
var a = {1: null};
console.log(a[1] === undefined); // output: false. I know the value at position 1 of a[] is absent and this was by design, i.e.: the value is defined.
console.log(a[0] === undefined); // output: true. I cannot say anything about a[0] value. In this case, the key 0 was not in a[].
Advice
Avoid objects with undefined values. Check directly whenever possible and use null to initialize property values. Otherwise, use the slow in operator or hasOwnProperty() method.
EDIT: 12/04/2018 - NOT RELEVANT ANYMORE
As people have commented, modern versions of the Javascript engines (with firefox exception) have changed the approach for access properties. The current implementation is slower than the previous one for this particular case but the difference between access key and object is neglectable.
It will return undefined.
var aa = {hello: "world"};
alert( aa["hello"] ); // popup box with "world"
alert( aa["goodbye"] ); // popup box with "undefined"
undefined is a special constant value. So you can say, e.g.
// note the three equal signs so that null won't be equal to undefined
if( aa["goodbye"] === undefined ) {
// do something
}
This is probably the best way to check for missing keys. However, as is pointed out in a comment below, it's theoretically possible that you'd want to have the actual value be undefined. I've never needed to do this and can't think of a reason offhand why I'd ever want to, but just for the sake of completeness, you can use the in operator
// this works even if you have {"goodbye": undefined}
if( "goodbye" in aa ) {
// do something
}
"key" in obj
Is likely testing only object attribute values that are very different from array keys
Checking for properties of the object including inherited properties
Could be determined using the in operator which returns true if the specified property is in the specified object or its prototype chain, false otherwise
const person = { name: 'dan' };
console.log('name' in person); // true
console.log('age' in person); // false
Checking for properties of the object instance (not including inherited properties)
*2021 - Using the new method ***Object.hasOwn() as a replacement for Object.hasOwnProperty()
Object.hasOwn() is intended as a replacement for Object.hasOwnProperty() and is a new method available to use (yet still not fully supported by all browsers like safari yet but soon will be)
Object.hasOwn() is a static method which returns true if the specified object has the specified property as its own property. If the property is inherited, or does not exist, the method returns false.
const person = { name: 'dan' };
console.log(Object.hasOwn(person, 'name'));// true
console.log(Object.hasOwn(person, 'age'));// false
const person2 = Object.create({gender: 'male'});
console.log(Object.hasOwn(person2, 'gender'));// false
What is the motivation to use it over Object.prototype.hasOwnProperty? - It is recommended to this method use over the Object.hasOwnProperty() because it also works for objects created by using Object.create(null) and for objects that have overridden the inherited hasOwnProperty() method. Although it's possible to solve these kind of problems by calling Object.prototype.hasOwnProperty() on an external object, Object.hasOwn() overcome these problems, hence is preferred (see examples below)
let person = {
hasOwnProperty: function() {
return false;
},
age: 35
};
if (Object.hasOwn(person, 'age')) {
console.log(person.age); // true - the remplementation of hasOwnProperty() did not affect the Object
}
let person = Object.create(null);
person.age = 35;
if (Object.hasOwn(person, 'age')) {
console.log(person.age); // true - works regardless of how the object was created
}
More about Object.hasOwn can be found here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
Browser compatibility for Object.hasOwn - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility
The accepted answer refers to Object. Beware using the in operator on Array to find data instead of keys:
("true" in ["true", "false"])
// -> false (Because the keys of the above Array are actually 0 and 1)
To test existing elements in an Array: Best way to find if an item is in a JavaScript array?
Three ways to check if a property is present in a javascript object:
!!obj.theProperty
Will convert value to bool. returns true for all but the false value
'theProperty' in obj
Will return true if the property exists, no matter its value (even empty)
obj.hasOwnProperty('theProperty')
Does not check the prototype chain. (since all objects have the toString method, 1 and 2 will return true on it, while 3 can return false on it.)
Reference:
http://book.mixu.net/node/ch5.html
If you are using underscore.js library then object/array operations become simple.
In your case _.has method can be used. Example:
yourArray = {age: "10"}
_.has(yourArray, "age")
returns true
But,
_.has(yourArray, "invalidKey")
returns false
Answer:
if ("key" in myObj)
{
console.log("key exists!");
}
else
{
console.log("key doesn't exist!");
}
Explanation:
The in operator will check if the key exists in the object. If you checked if the value was undefined: if (myObj["key"] === 'undefined'), you could run into problems because a key could possibly exist in your object with the undefined value.
For that reason, it is much better practice to first use the in operator and then compare the value that is inside the key once you already know it exists.
Here's a helper function I find quite useful
This keyExists(key, search) can be used to easily lookup a key within objects or arrays!
Just pass it the key you want to find, and search obj (the object or array) you want to find it in.
function keyExists(key, search) {
if (!search || (search.constructor !== Array && search.constructor !== Object)) {
return false;
}
for (var i = 0; i < search.length; i++) {
if (search[i] === key) {
return true;
}
}
return key in search;
}
// How to use it:
// Searching for keys in Arrays
console.log(keyExists('apple', ['apple', 'banana', 'orange'])); // true
console.log(keyExists('fruit', ['apple', 'banana', 'orange'])); // false
// Searching for keys in Objects
console.log(keyExists('age', {'name': 'Bill', 'age': 29 })); // true
console.log(keyExists('title', {'name': 'Jason', 'age': 29 })); // false
It's been pretty reliable and works well cross-browser.
vanila js
yourObjName.hasOwnProperty(key) : true ? false;
If you want to check if the object has at least one property in es2015
Object.keys(yourObjName).length : true ? false
ES6 solution
using Array#some and Object.keys. It will return true if given key exists in the object or false if it doesn't.
var obj = {foo: 'one', bar: 'two'};
function isKeyInObject(obj, key) {
var res = Object.keys(obj).some(v => v == key);
console.log(res);
}
isKeyInObject(obj, 'foo');
isKeyInObject(obj, 'something');
One-line example.
console.log(Object.keys({foo: 'one', bar: 'two'}).some(v => v == 'foo'));
Optional chaining operator:
const invoice = {customer: {address: {city: "foo"}}}
console.log( invoice?.customer?.address?.city )
console.log( invoice?.customer?.address?.street )
console.log( invoice?.xyz?.address?.city )
See supported browsers list
For those which have lodash included in their project:There is a lodash _.get method which tries to get "deep" keys:
Gets the value at path of object. If the resolved value is undefined,
the defaultValue is returned in its place.
var object = { 'a': [{ 'b': { 'c': 3 } }] };
console.log(
_.get(object, 'a[0].b.c'), // => 3
_.get(object, ['a', '0', 'b', 'c']), // => 3
_.get(object, 'a.b.c'), // => undefined
_.get(object, 'a.b.c', 'default') // => 'default'
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
This will effectively check if that key, however deep, is defined and will not throw an error which might harm the flow of your program if that key is not defined.
To find if a key exists in an object, use
Object.keys(obj).includes(key)
The ES7 includes method checks if an Array includes an item or not, & is a simpler alternative to indexOf.
The easiest way to check is
"key" in object
for example:
var obj = {
a: 1,
b: 2,
}
"a" in obj // true
"c" in obj // false
Return value as true implies that key exists in the object.
Optional Chaining (?.) operator can also be used for this
Source: MDN/Operators/Optional_chaining
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
}
console.log(adventurer.dog?.name) // undefined
console.log(adventurer.cat?.name) // Dinah
An alternate approach using "Reflect"
As per MDN
Reflect is a built-in object that provides methods for interceptable
JavaScript operations.
The static Reflect.has() method works like the in operator as a
function.
var obj = {
a: undefined,
b: 1,
c: "hello world"
}
console.log(Reflect.has(obj, 'a'))
console.log(Reflect.has(obj, 'b'))
console.log(Reflect.has(obj, 'c'))
console.log(Reflect.has(obj, 'd'))
Should I use it ?
It depends.
Reflect.has() is slower than the other methods mentioned on the accepted answer (as per my benchmark test). But, if you are using it only a few times in your code, I don't see much issues with this approach.
We can use - hasOwnProperty.call(obj, key);
The underscore.js way -
if(_.has(this.options, 'login')){
//key 'login' exists in this.options
}
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
If you want to check for any key at any depth on an object and account for falsey values consider this line for a utility function:
var keyExistsOn = (o, k) => k.split(".").reduce((a, c) => a.hasOwnProperty(c) ? a[c] || 1 : false, Object.assign({}, o)) === false ? false : true;
Results
var obj = {
test: "",
locals: {
test: "",
test2: false,
test3: NaN,
test4: 0,
test5: undefined,
auth: {
user: "hw"
}
}
}
keyExistsOn(obj, "")
> false
keyExistsOn(obj, "locals.test")
> true
keyExistsOn(obj, "locals.test2")
> true
keyExistsOn(obj, "locals.test3")
> true
keyExistsOn(obj, "locals.test4")
> true
keyExistsOn(obj, "locals.test5")
> true
keyExistsOn(obj, "sdsdf")
false
keyExistsOn(obj, "sdsdf.rtsd")
false
keyExistsOn(obj, "sdsdf.234d")
false
keyExistsOn(obj, "2134.sdsdf.234d")
false
keyExistsOn(obj, "locals")
true
keyExistsOn(obj, "locals.")
false
keyExistsOn(obj, "locals.auth")
true
keyExistsOn(obj, "locals.autht")
false
keyExistsOn(obj, "locals.auth.")
false
keyExistsOn(obj, "locals.auth.user")
true
keyExistsOn(obj, "locals.auth.userr")
false
keyExistsOn(obj, "locals.auth.user.")
false
keyExistsOn(obj, "locals.auth.user")
true
Also see this NPM package: https://www.npmjs.com/package/has-deep-value
While this doesn't necessarily check if a key exists, it does check for the truthiness of a value. Which undefined and null fall under.
Boolean(obj.foo)
This solution works best for me because I use typescript, and using strings like so 'foo' in obj or obj.hasOwnProperty('foo')
to check whether a key exists or not does not provide me with intellisense.
const object1 = {
a: 'something',
b: 'something',
c: 'something'
};
const key = 's';
// Object.keys(object1) will return array of the object keys ['a', 'b', 'c']
Object.keys(object1).indexOf(key) === -1 ? 'the key is not there' : 'yep the key is exist';
In 'array' world we can look on indexes as some kind of keys. What is surprising the in operator (which is good choice for object) also works with arrays. The returned value for non-existed key is undefined
let arr = ["a","b","c"]; // we have indexes: 0,1,2
delete arr[1]; // set 'empty' at index 1
arr.pop(); // remove last item
console.log(0 in arr, arr[0]);
console.log(1 in arr, arr[1]);
console.log(2 in arr, arr[2]);
Worth noting that since the introduction of ES11 you can use the nullish coalescing operator, which simplifies things a lot:
const obj = {foo: 'one', bar: 'two'};
const result = obj.foo ?? "Not found";
The code above will return "Not found" for any "falsy" values in foo. Otherwise it will return obj.foo.
See Combining with the nullish coalescing operator
JS Double Exclamation !! sign may help in this case.
const cars = {
petrol:{
price: 5000
},
gas:{
price:8000
}
}
Suppose we have the object above and If you try to log car with petrol price.
=> console.log(cars.petrol.price);
=> 5000
You'll definitely get 5000 out of it. But what if you try to get an
electric car which does not exist then you'll get undefine
=> console.log(cars.electric);
=> undefine
But using !! which is its short way to cast a variable to be a
Boolean (true or false) value.
=> console.log(!!cars.electric);
=> false
In my case, I wanted to check an NLP metadata returned by LUIS which is an object. I wanted to check if a key which is a string "FinancialRiskIntent" exists as a key inside that metadata object.
I tried to target the nested object I needed to check -> data.meta.prediction.intents (for my own purposes only, yours could be any object)
I used below code to check if the key exists:
const hasKey = 'FinancialRiskIntent' in data.meta.prediction.intents;
if(hasKey) {
console.log('The key exists.');
}
else {
console.log('The key does not exist.');
}
This is checking for a specific key which I was initially looking for.
Hope this bit helps someone.
yourArray.indexOf(yourArrayKeyName) > -1
fruit = ['apple', 'grapes', 'banana']
fruit.indexOf('apple') > -1
true
fruit = ['apple', 'grapes', 'banana']
fruit.indexOf('apple1') > -1
false
for strict object keys checking:
const object1 = {};
object1.stackoverflow = 51;
console.log(object1.hasOwnProperty('stackoverflow'));
output: true
These example can demonstrate the differences between defferent ways. Hope it will help you to pick the right one for your needs:
// Lets create object `a` using create function `A`
function A(){};
A.prototype.onProtDef=2;
A.prototype.onProtUndef=undefined;
var a=new A();
a.ownProp = 3;
a.ownPropUndef = undefined;
// Let's try different methods:
a.onProtDef; // 2
a.onProtUndef; // undefined
a.ownProp; // 3
a.ownPropUndef; // undefined
a.whatEver; // undefined
a.valueOf; // ƒ valueOf() { [native code] }
a.hasOwnProperty('onProtDef'); // false
a.hasOwnProperty('onProtUndef'); // false
a.hasOwnProperty('ownProp'); // true
a.hasOwnProperty('ownPropUndef'); // true
a.hasOwnProperty('whatEver'); // false
a.hasOwnProperty('valueOf'); // false
'onProtDef' in a; // true
'onProtUndef' in a; // true
'ownProp' in a; // true
'ownPropUndef' in a; // true
'whatEver' in a; // false
'valueOf' in a; // true (on the prototype chain - Object.valueOf)
Object.keys(a); // ["ownProp", "ownPropUndef"]
const rawObject = {};
rawObject.propertyKey = 'somethingValue';
console.log(rawObject.hasOwnProperty('somethingValue'));
// expected output: true
checking particular key present in given object, hasOwnProperty will works here.
If you have ESLint configured in your project follows ESLint rule no-prototype-builtins. The reason why has been described in the following link:
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(object, key));
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));
New awesome solution with JavaScript Destructuring:
let obj = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
};
let {key1, key2, key3, key4} = obj;
// key1 = "value1"
// key2 = "value2"
// key3 = "value3"
// key4 = undefined
// Can easily use `if` here on key4
if(!key4) { console.log("key not present"); } // Key not present
Do check other use of JavaScript Destructuring
Is there a null coalescing operator in Javascript?
For example, in C#, I can do this:
String someString = null;
var whatIWant = someString ?? "Cookies!";
The best approximation I can figure out for Javascript is using the conditional operator:
var someString = null;
var whatIWant = someString ? someString : 'Cookies!';
Which is sorta icky IMHO. Can I do better?
Update
JavaScript now supports the nullish coalescing operator (??). It returns its right-hand-side operand when its left-hand-side operand is null or undefined, and otherwise returns its left-hand-side operand.
Old Answer
Please check compatibility before using it.
The JavaScript equivalent of the C# null coalescing operator (??) is using a logical OR (||):
var whatIWant = someString || "Cookies!";
There are cases (clarified below) that the behaviour won't match that of C#, but this is the general, terse way of assigning default/alternative values in JavaScript.
Clarification
Regardless of the type of the first operand, if casting it to a Boolean results in false, the assignment will use the second operand. Beware of all the cases below:
alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)
This means:
var whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
function coalesce() {
var len = arguments.length;
for (var i=0; i<len; i++) {
if (arguments[i] !== null && arguments[i] !== undefined) {
return arguments[i];
}
}
return null;
}
var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);
// xyz.val now contains 5
this solution works like the SQL coalesce function, it accepts any number of arguments, and returns null if none of them have a value. It behaves like the C# ?? operator in the sense that "", false, and 0 are considered NOT NULL and therefore count as actual values. If you come from a .net background, this will be the most natural feeling solution.
Yes, it is coming soon. See proposal here and implementation status here.
It looks like this:
x ?? y
Example
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false
If || as a replacement of C#'s ?? isn't good enough in your case, because it swallows empty strings and zeros, you can always write your own function:
function $N(value, ifnull) {
if (value === null || value === undefined)
return ifnull;
return value;
}
var whatIWant = $N(someString, 'Cookies!');
Nobody has mentioned in here the potential for NaN, which--to me--is also a null-ish value. So, I thought I'd add my two-cents.
For the given code:
var a,
b = null,
c = parseInt('Not a number'),
d = 0,
e = '',
f = 1
;
If you were to use the || operator, you get the first non-false value:
var result = a || b || c || d || e || f; // result === 1
If you use the new ?? (null coalescing) operator, you will get c, which has the value: NaN
vas result = a ?? b ?? c ?? d ?? e ?? f; // result === NaN
Neither of these seem right to me. In my own little world of coalesce logic, which may differ from your world, I consider undefined, null, and NaN as all being "null-ish". So, I would expect to get back d (zero) from the coalesce method.
If anyone's brain works like mine, and you want to exclude NaN, then this custom coalesce method (unlike the one posted here) will accomplish that:
function coalesce() {
var i, undefined, arg;
for( i=0; i < arguments.length; i++ ) {
arg = arguments[i];
if( arg !== null && arg !== undefined
&& (typeof arg !== 'number' || arg.toString() !== 'NaN') ) {
return arg;
}
}
return null;
}
For those who want the code as short as possible, and don't mind a little lack of clarity, you can also use this as suggested by #impinball. This takes advantage of the fact that NaN is never equal to NaN. You can read up more on that here: Why is NaN not equal to NaN?
function coalesce() {
var i, arg;
for( i=0; i < arguments.length; i++ ) {
arg = arguments[i];
if( arg != null && arg === arg ) { //arg === arg is false for NaN
return arg;
}
}
return null;
}
Logical nullish assignment, 2020+ solution
A new operator is currently being added to the browsers, ??=. This combines the null coalescing operator ?? with the assignment operator =.
NOTE: This is not common in public browser versions yet. Will update as availability changes.
??= checks if the variable is undefined or null, short-circuiting if already defined. If not, the right-side value is assigned to the variable.
Basic Examples
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array Examples
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
Browser Support Jan '22 - 89%
Mozilla Documentation
Yes, and its proposal is Stage 4 now. This means that the proposal is ready for inclusion in the formal ECMAScript standard. You can already use it in recent desktop versions of Chrome, Edge and Firefox, but we will have to wait for a bit longer until this feature reaches cross-browser stability.
Have a look at the following example to demonstrate its behavior:
// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = undefined;
const var2 = "fallback value";
const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);
Previous example is equivalent to:
const var1 = undefined;
const var2 = "fallback value";
const result = (var1 !== null && var1 !== undefined) ?
var1 :
var2;
console.log(`Nullish coalescing results in: ${result}`);
Note that nullish coalescing will not threat falsy values the way the || operator did (it only checks for undefined or null values), hence the following snippet will act as follows:
// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = ""; // empty string
const var2 = "fallback value";
const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);
For TypesScript users, starting off TypeScript 3.7, this feature is also available now.
?? vs || vs &&
None of the other answers compares all three of these. Since Justin Johnson's comment has so many votes, and since double question mark vs && in javascript was marked a duplicate of this one, it makes sense to include && in an answer.
First in words, inspired by Justin Johnson's comment:
|| returns the first "truey" value, else the last value whatever it is.
&& returns the first "falsey" value, else the last value whatever it is.
?? returns the first non-null, non-undefined value, else the last value, whatever it is.
Then, demonstrated in live code:
let F1,
F2 = null,
F3 = 0,
F4 = '',
F5 = parseInt('Not a number (NaN)'),
T1 = 3,
T2 = 8
console.log( F1 || F2 || F3 || F4 || F5 || T1 || T2 ) // 3 (T1)
console.log( F1 || F2 || F3 || F4 || F5 ) // NaN (F5)
console.log( T1 && T2 && F1 && F2 && F3 && F4 && F5 ) // undefined (F1)
console.log( T1 && T2 ) // 8 (T2)
console.log( F1 ?? F2 ?? F3 ?? F4 ?? F5 ?? T1 ) // 0 (F3)
console.log( F1 ?? F2) // null (F2)
After reading your clarification, #Ates Goral's answer provides how to perform the same operation you're doing in C# in JavaScript.
#Gumbo's answer provides the best way to check for null; however, it's important to note the difference in == versus === in JavaScript especially when it comes to issues of checking for undefined and/or null.
There's a really good article about the difference in two terms here. Basically, understand that if you use == instead of ===, JavaScript will try to coalesce the values you're comparing and return what the result of the comparison after this coalescence.
beware of the JavaScript specific definition of null. there are two definitions for "no value" in javascript.
1. Null: when a variable is null, it means it contains no data in it, but the variable is already defined in the code. like this:
var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts
in such case, the type of your variable is actually Object. test it.
window.alert(typeof myEmptyValue); // prints Object
Undefined: when a variable has not been defined before in the code, and as expected, it does not contain any value. like this:
if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
// alerts
if such case, the type of your variable is 'undefined'.
notice that if you use the type-converting comparison operator (==), JavaScript will act equally for both of these empty-values. to distinguish between them, always use the type-strict comparison operator (===).
Note that React's create-react-app tool-chain supports the null-coalescing since version 3.3.0 (released 5.12.2019). From the release notes:
Optional Chaining and Nullish Coalescing Operators
We now support the optional chaining and nullish coalescing operators!
// Optional chaining
a?.(); // undefined if `a` is null/undefined
b?.c; // undefined if `b` is null/undefined
// Nullish coalescing
undefined ?? 'some other default'; // result: 'some other default'
null ?? 'some other default'; // result: 'some other default'
'' ?? 'some other default'; // result: ''
0 ?? 300; // result: 0
false ?? true; // result: false
This said, in case you use create-react-app 3.3.0+ you can start using the null-coalesce operator already today in your React apps.
There are two items here:
Logical OR
const foo = '' || 'default string';
console.log(foo); // output is 'default string'
Nullish coalescing operator
const foo = '' ?? 'default string';
console.log(foo); // output is empty string i.e. ''
The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
It will hopefully be available soon in Javascript, as it is in proposal phase as of Apr, 2020. You can monitor the status here for compatibility and support - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
For people using Typescript, you can use the nullish coalescing operator from Typescript 3.7
From the docs -
You can think of this feature - the ?? operator - as a way to “fall
back” to a default value when dealing with null or undefined. When we
write code like
let x = foo ?? bar();
this is a new way to say that the value foo will be used when it’s “present”; but when it’s null or undefined,
calculate bar() in its place.
Need to support old browser and have a object hierarchy
body.head.eyes[0] //body, head, eyes may be null
may use this,
(((body||{}) .head||{}) .eyes||[])[0] ||'left eye'
ECMAScript 2021 enabled two new features:
Nullish coalescing operator (??) which is a logical operator that returns its right-hand side operand when its left-hand side operand is either null or undefined, and otherwise returns its left-hand side operand.
let b = undefined ?? 5;
console.log(b); // 5
Logical nullish assignment (x ??= y) operator which only assigns if x has a nullish value (null or undefined).
const car = {speed : 20};
car.speed ??= 5;
console.log(car.speed);
car.name ??= "reno";
console.log(car.name);
More about Logical nullish assignment can be found here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment
More about Nullish coalescing operator can be found here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
Now it has full support in latest version of major browsers like Chrome, Edge, Firefox , Safari etc. Here's the comparison between the null operator and Nullish Coalescing Operator
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
/* OR Operator */
const undefinedValue = response.settings.undefinedValue || 'Default Value'; // 'Default Value'
const nullValue = response.settings.nullValue || 'Default Value'; // 'Default Value'
const headerText = response.settings.headerText || 'Hello, world!'; // 'Hello, world!'
const animationDuration = response.settings.animationDuration || 300; // 300
const showSplashScreen = response.settings.showSplashScreen || true; // true
/* Nullish Coalescing Operator */
const undefinedValue = response.settings.undefinedValue ?? 'Default Value'; // 'Default Value'
const nullValue = response.settings.nullValue ?? ''Default Value'; // 'Default Value'
const headerText = response.settings.headerText ?? 'Hello, world!'; // ''
const animationDuration = response.settings.animationDuration ?? 300; // 0
const showSplashScreen = response.settings.showSplashScreen ?? true; // false
Those who are using Babel, need to upgrade to the latest version to use nullish coalescing (??):
Babel 7.8.0 supports the new ECMAScript 2020 features by default: you
don't need to enable individual plugins for nullish coalescing (??),
optional chaining (?.) and dynamic import() anymore with preset-env
From https://babeljs.io/blog/2020/01/11/7.8.0
Chain multiple values / several values
"short circuit" is enabled: do not evaluate any further if one of the first values is valid
that means order matters, the most left values are prioritized
const value = first ?? second ?? third ?? "default";
I was trying to check if an input is null and then use the value accordingly. This is my code.
let valueToBeConsidered = !inputValue ? "trueCondition" : "falseCondition",
So if inputValue is null then valueToBeConsidered = falseCondition and if inputValue has a value then valueToBeConsidered = trueCondition
Is there a null coalescing operator in Javascript?
For example, in C#, I can do this:
String someString = null;
var whatIWant = someString ?? "Cookies!";
The best approximation I can figure out for Javascript is using the conditional operator:
var someString = null;
var whatIWant = someString ? someString : 'Cookies!';
Which is sorta icky IMHO. Can I do better?
Update
JavaScript now supports the nullish coalescing operator (??). It returns its right-hand-side operand when its left-hand-side operand is null or undefined, and otherwise returns its left-hand-side operand.
Old Answer
Please check compatibility before using it.
The JavaScript equivalent of the C# null coalescing operator (??) is using a logical OR (||):
var whatIWant = someString || "Cookies!";
There are cases (clarified below) that the behaviour won't match that of C#, but this is the general, terse way of assigning default/alternative values in JavaScript.
Clarification
Regardless of the type of the first operand, if casting it to a Boolean results in false, the assignment will use the second operand. Beware of all the cases below:
alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)
This means:
var whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
function coalesce() {
var len = arguments.length;
for (var i=0; i<len; i++) {
if (arguments[i] !== null && arguments[i] !== undefined) {
return arguments[i];
}
}
return null;
}
var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);
// xyz.val now contains 5
this solution works like the SQL coalesce function, it accepts any number of arguments, and returns null if none of them have a value. It behaves like the C# ?? operator in the sense that "", false, and 0 are considered NOT NULL and therefore count as actual values. If you come from a .net background, this will be the most natural feeling solution.
Yes, it is coming soon. See proposal here and implementation status here.
It looks like this:
x ?? y
Example
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false
If || as a replacement of C#'s ?? isn't good enough in your case, because it swallows empty strings and zeros, you can always write your own function:
function $N(value, ifnull) {
if (value === null || value === undefined)
return ifnull;
return value;
}
var whatIWant = $N(someString, 'Cookies!');
Nobody has mentioned in here the potential for NaN, which--to me--is also a null-ish value. So, I thought I'd add my two-cents.
For the given code:
var a,
b = null,
c = parseInt('Not a number'),
d = 0,
e = '',
f = 1
;
If you were to use the || operator, you get the first non-false value:
var result = a || b || c || d || e || f; // result === 1
If you use the new ?? (null coalescing) operator, you will get c, which has the value: NaN
vas result = a ?? b ?? c ?? d ?? e ?? f; // result === NaN
Neither of these seem right to me. In my own little world of coalesce logic, which may differ from your world, I consider undefined, null, and NaN as all being "null-ish". So, I would expect to get back d (zero) from the coalesce method.
If anyone's brain works like mine, and you want to exclude NaN, then this custom coalesce method (unlike the one posted here) will accomplish that:
function coalesce() {
var i, undefined, arg;
for( i=0; i < arguments.length; i++ ) {
arg = arguments[i];
if( arg !== null && arg !== undefined
&& (typeof arg !== 'number' || arg.toString() !== 'NaN') ) {
return arg;
}
}
return null;
}
For those who want the code as short as possible, and don't mind a little lack of clarity, you can also use this as suggested by #impinball. This takes advantage of the fact that NaN is never equal to NaN. You can read up more on that here: Why is NaN not equal to NaN?
function coalesce() {
var i, arg;
for( i=0; i < arguments.length; i++ ) {
arg = arguments[i];
if( arg != null && arg === arg ) { //arg === arg is false for NaN
return arg;
}
}
return null;
}
Logical nullish assignment, 2020+ solution
A new operator is currently being added to the browsers, ??=. This combines the null coalescing operator ?? with the assignment operator =.
NOTE: This is not common in public browser versions yet. Will update as availability changes.
??= checks if the variable is undefined or null, short-circuiting if already defined. If not, the right-side value is assigned to the variable.
Basic Examples
let a // undefined
let b = null
let c = false
a ??= true // true
b ??= true // true
c ??= true // false
Object/Array Examples
let x = ["foo"]
let y = { foo: "fizz" }
x[0] ??= "bar" // "foo"
x[1] ??= "bar" // "bar"
y.foo ??= "buzz" // "fizz"
y.bar ??= "buzz" // "buzz"
x // Array [ "foo", "bar" ]
y // Object { foo: "fizz", bar: "buzz" }
Browser Support Jan '22 - 89%
Mozilla Documentation
Yes, and its proposal is Stage 4 now. This means that the proposal is ready for inclusion in the formal ECMAScript standard. You can already use it in recent desktop versions of Chrome, Edge and Firefox, but we will have to wait for a bit longer until this feature reaches cross-browser stability.
Have a look at the following example to demonstrate its behavior:
// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = undefined;
const var2 = "fallback value";
const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);
Previous example is equivalent to:
const var1 = undefined;
const var2 = "fallback value";
const result = (var1 !== null && var1 !== undefined) ?
var1 :
var2;
console.log(`Nullish coalescing results in: ${result}`);
Note that nullish coalescing will not threat falsy values the way the || operator did (it only checks for undefined or null values), hence the following snippet will act as follows:
// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = ""; // empty string
const var2 = "fallback value";
const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);
For TypesScript users, starting off TypeScript 3.7, this feature is also available now.
?? vs || vs &&
None of the other answers compares all three of these. Since Justin Johnson's comment has so many votes, and since double question mark vs && in javascript was marked a duplicate of this one, it makes sense to include && in an answer.
First in words, inspired by Justin Johnson's comment:
|| returns the first "truey" value, else the last value whatever it is.
&& returns the first "falsey" value, else the last value whatever it is.
?? returns the first non-null, non-undefined value, else the last value, whatever it is.
Then, demonstrated in live code:
let F1,
F2 = null,
F3 = 0,
F4 = '',
F5 = parseInt('Not a number (NaN)'),
T1 = 3,
T2 = 8
console.log( F1 || F2 || F3 || F4 || F5 || T1 || T2 ) // 3 (T1)
console.log( F1 || F2 || F3 || F4 || F5 ) // NaN (F5)
console.log( T1 && T2 && F1 && F2 && F3 && F4 && F5 ) // undefined (F1)
console.log( T1 && T2 ) // 8 (T2)
console.log( F1 ?? F2 ?? F3 ?? F4 ?? F5 ?? T1 ) // 0 (F3)
console.log( F1 ?? F2) // null (F2)
After reading your clarification, #Ates Goral's answer provides how to perform the same operation you're doing in C# in JavaScript.
#Gumbo's answer provides the best way to check for null; however, it's important to note the difference in == versus === in JavaScript especially when it comes to issues of checking for undefined and/or null.
There's a really good article about the difference in two terms here. Basically, understand that if you use == instead of ===, JavaScript will try to coalesce the values you're comparing and return what the result of the comparison after this coalescence.
beware of the JavaScript specific definition of null. there are two definitions for "no value" in javascript.
1. Null: when a variable is null, it means it contains no data in it, but the variable is already defined in the code. like this:
var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts
in such case, the type of your variable is actually Object. test it.
window.alert(typeof myEmptyValue); // prints Object
Undefined: when a variable has not been defined before in the code, and as expected, it does not contain any value. like this:
if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
// alerts
if such case, the type of your variable is 'undefined'.
notice that if you use the type-converting comparison operator (==), JavaScript will act equally for both of these empty-values. to distinguish between them, always use the type-strict comparison operator (===).
Note that React's create-react-app tool-chain supports the null-coalescing since version 3.3.0 (released 5.12.2019). From the release notes:
Optional Chaining and Nullish Coalescing Operators
We now support the optional chaining and nullish coalescing operators!
// Optional chaining
a?.(); // undefined if `a` is null/undefined
b?.c; // undefined if `b` is null/undefined
// Nullish coalescing
undefined ?? 'some other default'; // result: 'some other default'
null ?? 'some other default'; // result: 'some other default'
'' ?? 'some other default'; // result: ''
0 ?? 300; // result: 0
false ?? true; // result: false
This said, in case you use create-react-app 3.3.0+ you can start using the null-coalesce operator already today in your React apps.
There are two items here:
Logical OR
const foo = '' || 'default string';
console.log(foo); // output is 'default string'
Nullish coalescing operator
const foo = '' ?? 'default string';
console.log(foo); // output is empty string i.e. ''
The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
It will hopefully be available soon in Javascript, as it is in proposal phase as of Apr, 2020. You can monitor the status here for compatibility and support - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
For people using Typescript, you can use the nullish coalescing operator from Typescript 3.7
From the docs -
You can think of this feature - the ?? operator - as a way to “fall
back” to a default value when dealing with null or undefined. When we
write code like
let x = foo ?? bar();
this is a new way to say that the value foo will be used when it’s “present”; but when it’s null or undefined,
calculate bar() in its place.
Need to support old browser and have a object hierarchy
body.head.eyes[0] //body, head, eyes may be null
may use this,
(((body||{}) .head||{}) .eyes||[])[0] ||'left eye'
ECMAScript 2021 enabled two new features:
Nullish coalescing operator (??) which is a logical operator that returns its right-hand side operand when its left-hand side operand is either null or undefined, and otherwise returns its left-hand side operand.
let b = undefined ?? 5;
console.log(b); // 5
Logical nullish assignment (x ??= y) operator which only assigns if x has a nullish value (null or undefined).
const car = {speed : 20};
car.speed ??= 5;
console.log(car.speed);
car.name ??= "reno";
console.log(car.name);
More about Logical nullish assignment can be found here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment
More about Nullish coalescing operator can be found here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
Now it has full support in latest version of major browsers like Chrome, Edge, Firefox , Safari etc. Here's the comparison between the null operator and Nullish Coalescing Operator
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
/* OR Operator */
const undefinedValue = response.settings.undefinedValue || 'Default Value'; // 'Default Value'
const nullValue = response.settings.nullValue || 'Default Value'; // 'Default Value'
const headerText = response.settings.headerText || 'Hello, world!'; // 'Hello, world!'
const animationDuration = response.settings.animationDuration || 300; // 300
const showSplashScreen = response.settings.showSplashScreen || true; // true
/* Nullish Coalescing Operator */
const undefinedValue = response.settings.undefinedValue ?? 'Default Value'; // 'Default Value'
const nullValue = response.settings.nullValue ?? ''Default Value'; // 'Default Value'
const headerText = response.settings.headerText ?? 'Hello, world!'; // ''
const animationDuration = response.settings.animationDuration ?? 300; // 0
const showSplashScreen = response.settings.showSplashScreen ?? true; // false
Those who are using Babel, need to upgrade to the latest version to use nullish coalescing (??):
Babel 7.8.0 supports the new ECMAScript 2020 features by default: you
don't need to enable individual plugins for nullish coalescing (??),
optional chaining (?.) and dynamic import() anymore with preset-env
From https://babeljs.io/blog/2020/01/11/7.8.0
Chain multiple values / several values
"short circuit" is enabled: do not evaluate any further if one of the first values is valid
that means order matters, the most left values are prioritized
const value = first ?? second ?? third ?? "default";
I was trying to check if an input is null and then use the value accordingly. This is my code.
let valueToBeConsidered = !inputValue ? "trueCondition" : "falseCondition",
So if inputValue is null then valueToBeConsidered = falseCondition and if inputValue has a value then valueToBeConsidered = trueCondition
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 "".
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
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
You can achieve roughly the same effect by saying:
var displayName = user.name || "Anonymous";
UPDATE SEP 2019
Yes, JS now supports this.
Optional chaining is coming soon to v8 read more
This is more commonly known as a null-coalescing operator. Javascript does not have one.
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!
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.
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);
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.
https://github.com/tc39/proposal-optional-chaining
https://www.npmjs.com/package/#babel/plugin-proposal-optional-chaining
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 :)
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();
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';
?? would work in js which is equivalent to ?: in kotlin
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');