This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Closed 5 years ago.
I have a large json object. I need to access x = a.b.c.d.e.f.g. However b (or c, d, e...) can be undefined. This data structure is being imported from somewhere else.
Is there a way to try to get to assign x with null or undefined without throwing an error?
Update
Optional chaining is now part of the ECMAScript spec and can be used on most javascript clients (browsers, node.js, etc)
x = a.b?.c?.d?.e?.f?.g
To use a default value if the access fails you can use the Nullish coalescing operator (??)
x = a.b?.c?.d?.e?.f?.g ?? 'my default value'
original answer (2017)
The easiest way is to use try catch
try {
x = a.b.c.d.e.f.g
} catch(e) {
x = undefined;
}
There is a proposal for this called optional chaining you can check it here: https://github.com/tc39/proposal-optional-chaining
x = a.b?.c?.d?.e?.f?.g
If you are using a transpiler you'll be able to use it, however its still in the very early stages and might not be accepted to be supported in the spec
There are some proposals to solve this ( syntactic sugar missing) problem. Hopefully somewhen we may do this:
let x = a?.b?.c?.d?.e;
However, until then we need to fall back to objects if the variable is undefined:
var x =( ( ( ( (a || {}).b || {} ) || {} ).c || {} ).d || {}).e;
I admit that this is quite ugly. Maybe object destructuring is more beautiful:
let ({
b: {
c: {
d: { e:x } = {}
} = {}
} = {}
}) = a;
Related
This question already has answers here:
How to use a variable for a key in a JavaScript object literal?
(16 answers)
Closed 4 months ago.
const A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
Result:
undefined
undefined
Second try:
var A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
Result:
undefined
undefined
How am I supposed to do this then? And can somebody explain why this doesn't work in JavaScript the way one would expect it to work coming from other languages?
The correct way is:
const A = 0;
const LOOKUP = {};
LOOKUP[A] = 'A';
console.log(LOOKUP[A]);
console.log(LOOKUP[0]);
const LOOKUP = { A : "A"};
The left side of the colon means that the key is the string "A". The string part is implicit, since all keys are strings (or symbols). So to access the property, you need to do console.log(LOOKUP.A) or console.log(LOOKUP["A"])
If you want the key to be a computed value, then you need to use square brackets:
const LOOKUP = { [A]: "A" };
That means that we should resolve the variable A, and use its value as the key. That key is the number 0, which then gets coerced into the string "0". You can then look it up by any of console.log(LOOKUP["0"]), console.log(LOOKUP[0]), or console.log(LOOKUP[A])
Looks like you are searching for some enums (typescript):
enum ETest {
A = 1
};
console.log(ETest['A']); // 1
console.log(ETest[1]); // A
Doing LOOKUP[A] is like doing LOOKUP[0] which is undefined.
You should try it as
console.log(LOOKUP["A"])
This has nothing to do with const or var keyword. The way you are trying to access an object property is incorrect.
const A = 0;
const LOOKUP = { A : "A"};
console.log(LOOKUP["A"]); // Correct Approach: Property access through bracket notation should be done using a string (or a variable assigned to a string).
console.log(LOOKUP[0]); // Property `0` doesn't exist on object `LOOKUP`, so it'll return `undefined`.
This question already has answers here:
Is there a null-coalescing (Elvis) operator or safe navigation operator in javascript?
(22 answers)
Closed 4 years ago.
I'm wondering if there's a shorthand way to write something like this in JavaScript
if (thingExists) {
thingExists.manipulate
}
I think I remember seeing something along the lines of
thingExists?.manipulate
but that may have been TypeScript or something.
Anyway, any knowledge on that matter is appreciated,
Thanks!
You can use && for short circuiting:
thingExists && thingExists.manipulate
thingExists.manipulate will be evaluated if and only if thingExists is truthy.
Example:
var obj = { func: function() { console.log("func is called"); } };
obj && obj.func(); // => func is called
var falsy = null;
falsy && falsy.imaginaryFunc(); // => nothing
This question already has answers here:
if (key in object) or if(object.hasOwnProperty(key)
(9 answers)
Closed 4 years ago.
I was wondering if there was a standard library or external library (eg lodash) function that essentially does following:
function f(options) {
const x = options.x;
if (x === null || x === undefined) throw new Error('x is required option');
...
}
I have searched various key words in the lodash documentation but have yet to find something like this.
To check if a property exists, you can just write if(x in options)... Libraries exist to make tedious or difficult operations simple, This is such a simple operation that no library is needed and you'd be unlikely to find it added to a library.
While .hasOwnProperty() can work, it will only test for properties attached directly to the object in quesiton, while the in approach tests for inherited properties as well.
But, be careful about throwing errors. It's not generally something that you want to do for performance reasons. It's better to return a code or message.
var options = {
foo:42,
bar:"doesn't matter"
};
function propTest(propName, obj){
// Instead of throwing an error, return a value that indicates success or not
return (propName in obj) ? true : false;
}
console.log(propTest("foo", options));
console.log(propTest("bar", options));
console.log(propTest("baz", options));
You can write a function that iterates through an objects keys and looks for undefined ones
function CheckObjectProperties(obj)
{
for (var key in obj)
{
if(!obj[key])
{
throw new Error('Object has one or more undefined members');
}
}
}
or if you wanna check if an unknown object you can do something along the line of this. This approach is much more dynamic and reusable :D
function CheckObjectForProperties(obj, arraryOfStringProperties)
{
for(let i = 0; i < arraryOfStringProperties.length; i++)
{
let key = arraryOfStringProperties[i];
if(!obj[key])
{
throw new Error('Member not Found in Given Object.');
}
}
}
let myObject = {
x : 1,
y : 2,
z : undefined
}
let requiredProperties = ['x', 'y', 'z'];
CheckObjectForProperties(myObject, requiredProperties);
This question already has answers here:
Get the description of a ES6 Symbol
(4 answers)
Closed 5 years ago.
Suppose I have a symbol such as const sym = Symbol('foo');. Now, is there a way to get the value foo from that symbol without relying on string manipulations?
I expected sym.toString() to return 'foo' but it returns Symbol(foo).
Update
I settled with this hacky solution, until I find a better one :)
const key = Symbol.keyFor(sym) || (sym = sym.toString(), sym.substring(7, sym.length - 1));
There is the Symbol.keyFor. But it only works with the globally registered symbols
const works = Symbol.for('foo');
const key1 = Symbol.keyFor(works); // "foo"
const doesNotWork = Symbol('foo');
const key2 = Symbol.keyFor(doesNotWork); // undefined
I'm guessing that the private symbols do this by design. You could always monkey patch it:
const patched = Symbol('foo');
patched.key = 'foo';
This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Closed 6 years ago.
This is something that I come up against quite often in Javascript. Let's say I have an object like this:
var acquaintances = {
types: {
friends: {
billy: 6,
jascinta: 44,
john: 91
others: ["Matt", "Phil", "Jenny", "Anna"]
},
coworkers: {
matt: 1
}
}
}
In my theoretical program, all I know for sure is that acquaintances is an object; I have no idea whether acquaintances.types has been set, or whether friends has been set within it.
How can I efficiently check whether acquaintances.types.friends.others exists?
What I would normally do is:
if(acquaintances.types){
if(aquaintances.types.friends){
if(acquaintances.types.friends.others){
// do stuff with the "others" array here
}
}
}
Aside from being laborious, these nested if statements are a bit of a nightmare to manage (in practice my objects have far more levels than this!). But if I were to just try something like if(acquaintances.types.friends.others){) straight off the bat, and types hasn't been set yet, then the program will crash.
What ways does Javascript have of doing this in a neat, manageable way?
An alternative approach is:
((acquaintances.types || {}).friends || {}).others
which is shorter than other solutions, but may or may not thrill you.
You can also build a little helper to make the same idea a tiny bit more palatable:
function maybe(o) { return o || {}; }
Now you can do
maybe(maybe(acquaintances.types).friends).others
If you don't mind writing property names as strings, you could make a little helper:
function maybe(obj) {
return Object.defineProperty(
obj || {},
'get',
{ value: function(prop) { return maybe(obj[prop]); }
);
}
Now you can write
maybe(acquaintances.types').get('friends').others
In ES6, you can do this, albeit clumsily, using destructuring assignment with defaults:
var { types: { friends: { others } = {} } = {} } = acquaintances;
If you want to use this in an expression context, instead of assigning to a variable, in theory you could use argument destructuring:
(({ types: { friends: { others } = {} } = {} }) => others)(acquaintances)
After all is said and done, the standard approach remains
acquaintances.types &&
acquaintances.types.friends &&
acquaintances.types.friends.others
This is why there is an active (?) discussion in the ES6 design groups about a CoffeeScript-like existential operator, but it does not seem to be converging very rapidly.
The and operator is sequential so you can do this without nesting if statements.
if(acquaintances.types && aquaintances.types.friends && acquaintances.types.friends.others){
//acquaintances.types.friends.others exists!
}
It's not nice in JavaScript.
You could add them to one big condition...
if (obj.prop && obj.prop.someOtherProp) { }
...or write a helper function where you pass an object and a string...
var isPropSet = function(object, propPath) {
return !! propPath.split('.')
.reduce(function(object, prop) { return object[prop] || {}; }, object);
};
isPropSet(obj, 'prop.someOtherProp);
...or you could use CoffeeScript and its ? operator...
obj.prop?.someOtherProp
You could also wrap the lookup in a try/catch, but I wouldn't recommend it.
Instead of this:
if(acquaintances.types){
if(aquaintances.types.friends){
if(acquaintances.types.friends.others){
// do stuff with the "others" array here
}
}
}
Try this:
if(acquaintances &&
acquaintances.types &&
acquaintances.types.friends &&
acquaintances.types.friends.others) {
}
Or
acquaintances &&
acquaintances.types &&
acquaintances.types.friends &&
acquaintances.types.friends.others ?
doSomething() : doSomethingElse()