Lesson Weekend

Let's take a brief break from the address book project we just started to learn how to create an object that contains another object. Then we'll use this to build out our address book in the next lesson.

We'll begin by making some objects that represent cities and countries:

let pdx = { name: "Portland" };
let sfo = { name: "San Francisco" };
let sea = { name: "Seattle" };
let cso = { name: "Aktau" };
let dzn = { name: "Zhezkazgan" };

let usa = { name: "United States of America" };
let kazakhstan = { name: "Kazakhstan" };
let uruguay = { name: "Uruguay" };

Very often, we'll want to create associations between objects; for example, we may want to know a list of cities in a particular country. Here's how we can do this:

let pdx = { name: "Portland" };
let sfo = { name: "San Francisco" };
let sea = { name: "Seattle" };
let cso = { name: "Aktau" };
let dzn = { name: "Zhezkazgan" };

let usa = { name: "United States of America", cities: [pdx, sfo, sea] };
let kazakhstan = { name: "Kazakhstan", cities: [cso, dzn] };
let uruguay = { name: "Uruguay", cities: [] };

Let's take a look at the properties of usa - and also how we could get to the name of pdx from usa:

> usa.name;
"United States of America"
> usa.cities;
[pdx, sfo, sea]
> usa.cities[0];
pdx
> usa.cities[0].name;
"Portland"

As we can see, all of the pieces of information stored inside an object's properties is accessible. However, accessing more deeply nested properties is often a huge point of confusion for beginners. In the example above, we can see that usa.cities is the array of cities we created. We can use bracket notation to get the first city pdx from that array - after all, it works like any other array. We can also loop through that array:

usa.cities.forEach(function(city) {
  console.log("Let's go to " + city.name + "!");
});

We can also add cities to a country after the object is initially created:

let mlz = { name: "Melo" };
uruguay.cities.push(mlz);

uruguay.cities returns an array, and then we push() the new object onto the array.

When retrieving more deeply nested properties, it's important to note the type of object you are working with. Let's look at a slightly more confusing object that holds a variety of objects, arrays, and strings:

let boxOfStuff = {
  book: "Object-Oriented JavaScript",
  smallerBox: {
    stuff: ["pencils", "pens"],
    smallestBox: {
      stuff: ["paper clips", "thumbtacks"]
    }
  }
};

While we could write out this entire nested object in a single line, it's much more readable using indentation. Each layer of nesting results in an extra level of indentation with the most nested object (smallestBox) being the most indented.

See if you can access "pens" and "paper clips" in the console before moving on.

Now let's take a look at how we can access different things inside our jumbled boxOfStuff.

Getting out the book is easy:

> boxOfStuff.book;
"Object-Oriented JavaScript"

Note that we can also use bracket notation to retrieve this property, though you won't see this as often:

> boxOfStuff["book"];
"Object-Oriented JavaScript"

Note that the property has to be in string form to do this. boxOfStuff[book] will not work. We recommend using dot notation, not bracket notation, for grabbing object properties.

Now that we've gotten the book out of the box, let's see how we can get out the "pens" and "paper clips" so we can make notes in the book. Here's how we can grab the pens:

boxOfStuff.smallerBox.stuff[1];

It's a bit tricky because pens is inside an array inside stuff which is an object inside smallerBox which is itself an object inside of boxOfStuff. We have to deal with both objects and arrays to get our pens.

Now let's get the paper clips:

boxOfStuff.smallerBox.smallestBox.stuff[0];

We have to go another level deeper to retrieve the smallestBox object, which is a property of smallerBox. Note that the stuff inside smallestBox is a completely different property than the stuff inside smallerBox. We have two different objects that both have a property named stuff. They are different properties, though, just like two people named Jane are different people.

If getting properties from this object was a bit confusing, that's okay. It was meant to be a confusing object. You'll find plenty of other confusing objects out in the wild, though! Don't forget that you can always explore an object one level at a time in the console:

We can look at an object's properties in the console, then dig deeper and look more closely at the objects inside of the objects.

In the GIF above, we use the console to navigate through boxOfStuff, gradually getting closer to the array that contains "paper clips".

Let's look at one more example of objects within objects. This is another tricky one, which is by design.

let tomatoes = { name: "Tomatoes", price: 2.99 };
let cucumbers = { name: "Cucumbers", price: 0.99 };
let onions = { name: "Onions", price: 0.79 };

let groceryStore = { name: "Michael's corner market", products: [tomatoes, cucumbers, onions] };

let iPhone = { name: "iPhone", price: 699 };
let android = { name: "Android", price: 499 };
let windowsPhone = { name: "Windows Phone", price: 399 };

let phoneStore = { name: "RadioShack", products: [iPhone, android, windowsPhone] };

let stores = [groceryStore, phoneStore];

stores.forEach(function(store) {
  console.log(store.name + " sells:");
  store.products.forEach(function(product) {
    console.log(product.name);
  });
  console.log("\n");
});

We have several layers of nesting here. We have stores, which contains an array with both groceryStore and phoneStore. In turn, each of those stores has its own products - groceryStore has vegetables, phoneStore has phones.

We loop through each store, displaying its name, and then within each store, we loop again through the products it contains, displaying their names. Note that "\n" creates a new line. (A new line is the equivalent of hitting Enter twice to create space between two lines).

As you can see, we can do a lot with objects contained inside other objects. Working with properties and deeply-nested objects can be challenging at first. However, it's an important part of JavaScript. In fact, working with JavaScript objects like this is so common in the industry that JSON (JavaScript Object Notation) is a standard form of sharing data across many programming languages, not just JavaScript. We'll work more with JSON later - but for now, just be aware that being comfortable with navigating through JavaScript objects is an absolutely essential skill - and not too hard to master with a little practice.

Examples


To create relationships among objects, use properties whose values are arrays of other objects:

let pdx = { name: "Portland" };
let sfo = { name: "San Francisco" };
let sea = { name: "Seattle" };

let usa = { name: "United States of America", cities: [pdx, sfo, sea] };

To add multiple objects within an object, we can use an empty array:

let uruguay = { name: "Uruguay", cities: [] };

Then we can add more objects to the cities array:

let mlz = { name: "Melo" };
uruguay.cities.push(mlz);

Lesson 7 of 32
Last updated April 8, 2021