Register to get access to 15+ free programming courses with interactive exercises

Nested objects JS: Objects

The value of an object property can be anything, including another object or an array:

const user = { name: 'John', married: true, age: 25 };

// Adding a property called "friends" containing a list of friends
user.friends = ['Samuel', 'Kristian'];

// Adding a property called "children" with a list of children,
// each child is represented by a separate object
user.children = [
  { name: 'Nency', age: 1 },
  { name: 'Peter', age: 10 },
];

// Add a nested object
user.company = { name: 'Hexlet' };

console.log(user); // =>
// {
//   name: 'John',
//   married: true,
//   age: 25,
//   friends: [ 'Samuel', 'Kristian' ],
//   company: { name: 'Hexlet' },
//   children: [ { name: 'Nency', age: 1 }, { name: 'Peter', age: 10 } ]
// }

All of these can be defined immediately when you create an object:

const user = {
  name: 'John',
  married: true,
  age: 25,
  friends: ['Samuel', 'Kristian'],
  children: [
    { name: 'Nency', age: 1 },
    { name: 'Peter', age: 10 },
  ],
  company: {
    name: 'Hexlet'
  },
};

In this case, nested elements are accessed by chaining keys:

user.friends[1];       // 'Kristian'
user.children[0].name; // 'Nency'
user.company.name; // 'Hexlet'

Printing

There is one limitation built into console.log(). If an object has nested objects deeper than the second level, when printing such an object, a string, [Object], will be displayed instead of the object itself, and another string, [Array], will be displayed instead of an array.

const obj = { a: { b: { c: { key: 'value' }, e: [1, 2] } } };
console.log(obj);
// { a: { b: { c: [Object], e: [Array] } } }

You can use the JSON conversion function to output such objects:

console.log(JSON.stringify(obj));
// {"a":{"b":{"c":{"key":"value"},"e":[1,2]}}}

// or formatted output
console.log(JSON.stringify(obj, null, '  '));
// {
//   "a": {
//     "b": {
//       "c": {
//         "key": "value"
//       },
//       "e": [
//         1,
//         2
//       ]
//     }
//   }
// }

Checking nested objects

When working with nested objects, the task of checking that keys exist complicates dramatically. You have to build a chain of conditions for the desired property. Imagine we need to get to nesting level 4, and we're not certain that all the intermediate objects exist:

// Getting to obj.one.two.three
if (Object.hasOwn(obj, 'one')) {
  if (Object.hasOwn(obj.one, 'two')) {
    if (Object.hasOwn(obj.one.two, 'three')) {
      // ...
    }
  }
}

This is what a head-on solution would look like. However, there is a more convenient way, which will be discussed below.

Optional chaining operator

If the goal is to get the data and not just check that it exists, there is another way. JavaScript has a built-in optional chaining operator which allows you to extract nested data without any checks:

const obj = {};
obj?.one?.two?.three // undefined

This operator never causes an error. It works on any data type and always returns either undefined or the property value if it exists.

Nullish coalescing operator

With the nullish coalescing operator, you can do more than get a value in the chain at any nesting level, but also define a default value for it.

const obj = {};
obj?.one?.two?.three ?? 'defaultValue' // 'defaultValue'

The default value is only returned when undefined or null is on the left hand side. In this sense, this operator is not at all like the logical comparison ||:

const value = false;

value ?? 'default'; // false
value || 'default'; // 'default'

get (lodash)

The last example is overloaded with symbols and looks rather complicated. As an alternative, you can use the get() function from the lodash library.

import _ from 'lodash';

const obj = {};

const value = _.get(obj, 'one.two.three', 'defaultValue'); // 'defaultValue'

get() is especially useful for dynamic keys. In this case, you can pass an array of keys as the second argument:

_.get(obj, ['one', 'two', 'three'], 'defaultValue'); // 'defaultValue'

Recommended materials

  1. get() function from the lodash library

Аватары экспертов Хекслета

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs

From zero to a developer. Refunds in case you won't get a job

Frontend Developer icon
Profession
New
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions

Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.