Most efficient Javascript way to check if an object within an unknown object exists [duplicate]

2024/2/27 7:16:30

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: 91others: ["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?

Answer

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.

http://en.ppmy.cn/q/41804.html

Related Q&A

Protractor - Selecting Text

Im having some real trouble with selecting some text using protractor. A little context; this is for an AngularJS CMS system for writing news articles. The text I want to highlight is located within a …

javascript split regex bug in IE7

I am trying to split with this regex ({[^{}]*}) in javascript and I get different result btw IE7 and FF. The firefox result is the right one.<style> .box.round {border-radius: 10px; } </style&…

Mipmap a planet in three.js?

So I recently learned about the definition of mipmapping but im unsure of how to properly use that technique within three.js.I had a look at this example: http://threejs.org/examples/webgl_materials_t…

Calling function inside object using bracket notation

If i have a function defined inside some object as in :var myobject={ myfunction:function(){//mycode here} }usually you can access the function using:myobject.myfunction()but what if i want to usemyobj…

Any way to modify this in JavaScript?

I found this answer: How to modify "this" in javascriptBut I did not like it. Surely there must be a way to somehow modify this?Here is an example:(function() {var a = function(v){v += 10;a …

Ember.js - How to properly bind a collection to a view using Ember.Router?

I was previously working with Ember.StateManager and now Im doing some tests before I finally switch to Ember.Router, but Im failing to understand how to properly bind my view data from the collection …

Chart.js with dual axis on bar and line graph

I am using Quinces Chart.js version from this topic Chart.js how to get Combined Bar and line charts?. Bar and Line graph look very nice. Anyway, axis has to be separated into Y1 and Y2 which i cannot…

How to Swipe between surfaces in Famo.us?

Using the following Famo.us example code that adds 10 surfaces displayed vertically with 100% width and height, how can I add functionality to swipe between them, similar to how the swiping works on th…

google API translate, only a div into page

I have an HTML page, and I would use Google Translate to translate only a div into my page.<div id="google_translate_element"></div><script> function googleTranslateElementI…

Break D3 Each Loop Without a flag

Consider the following code:circle.each(function (d) {//...code });How can I break the loop? Is there a natural D3 way to break out of an each loop? I mean without a flag as follows:var flag = false;…