FORUM Menu

Arrays and Objects

by kirupa   |   filed under JavaScript 101

As we have seen so far, arrays are all about making it super simple to work with collections of data. This simplicity is partly through the various properties and methods available to us. It is also through the unique ways we have for accessing the data stored by our arrays using the bracket notation. Despite all the awesome things arrays have going for them, since we are still living inside a world whose boundaries are defined by JavaScript, our arrays are still just an extension of the humble Object.

This detail is important because it can help shed light on why our arrays behave the way they do when we use them in ways they both were and weren't designed for. We will dive deeper into all of this in the following sections.

Onwards!

Arrays are Objects

If we look at the prototype chain, an Array is just two degrees (using a Kevin Bacon-ism) removed from a plain old Object where we go from Array, to Array.prototype, to Object.prototype. The following diagram shows what this prototype chain looks like for an array called myItems storing the numbers 1, 2, and 3:

The main takeaway from seeing the prototype chain is this: our arrays provide a lot of capabilities, but if we deviate too far from their supported path, our array object will behave like a typical object...and all the opportunities and pitfalls that come from that.

This is most evident when it comes to using the bracket notation to access items in our array. Each array item has an index position/value, and this is represented as an integer that starts at 0 with the first item and goes up until we reach the last item at the end of our array:

This makes accessing array values straightforward where we use a bracket notation and specify the index position of the item we are interested in:

let greetings = ["hi", "sup", "hello", "yo", "hey"];
console.log(greetings[3]); // "yo"

Here is where things get a little muddy. Using this bracket notation to retrieve things isn't unique to arrays. It is a core part of how we can access values in regular objects as well:

let foo = { a: "hello", 
            b: "good bye!" 
          };

foo["c"] = "blah!";

console.log(foo["c"]); // "blah!";

The biggest difference in the bracket notation between arrays and objects has to do with what the key values can be. The key values we can specify for objects can be a lot of valid identifiers - numbers, text, and more. For arrays, the key has to be a positive integer value if we want the data we are dealing with to be treated like an array. This bolded part is important, because the following is totally valid:

let myArray = ["one", "two", "three"];
myArray["foo"] = "What's up?";

console.log(myArray[0]); // "one"
console.log(myArray["foo"]); // "What's up?"

If we visualize what the items stored bymyArray look like, this is what we will see:

At least, that is what we might expect to see given how effortlessly we were able to access the values stored in myArray using the key values of 0 and foo. What we actually have is a region of items that are a part of the Array world and a region that is part of the Object world:

The Array and Object regions are quite independent. All of the array operations only operate within this Array region. For example, checking the length of myArray will return 3. The length calculation won't cross into the Object region (aka the array's object property collection) and include the item stored at foo. Similarly, myArray.indexOf("what's up?") will return a -1 indicating it wasn't able to find "what's up?" as a value stored by our array. To say that arrays are territorial is an understatement!

Something about for...of and for...in!

When iterating over our arrays, especially if they happen to have both Array items and Object items as shown with myArray earlier, the behavior you will see when using for...of and for...in will vary. Take a look at the following code:

let myArray = ["one", "two", "three"];
myArray["foo"] = "What's up?";

// using for...of
for (const value of myArray) {
  console.log(value); // "one", "two", "three"
}

// using for...in
for (const key in myArray) {
  console.log(myArray[key]); // "one", "two", "three", "What's up?"
}

With for...of, what we will iterate through are just the values stored by our array. We won't be jumping into the Object region and accessing any values stored by our array's object property collection.

Things are different with for...in. What the for...in loop returns are all enumerable properties on an object. This means that what we will see are properties for both Arrays as well as properties on any prototypes like Object. If you rely on iterating through collections of data using for...in or for...of, these details may be important.

Conclusion

In JavaScript, everything inherits from Object. This is one of those truths that never quite hits our radar except when something isn't working right. Those somethings often crop up when we are working with types like Arrays where their behavior overlaps with Objects in some strange ways. Over the past many paragraphs, we looked at how Arrays and Objects allow us to store and retrieve data, but the similarities end very quickly where arrays live in their own world and objects live in theirs. The tricky part is that an array can live as both an array and object, so...yeah!

Got a question or just want to chat? Comment below or drop by our forums (they are actually the same thing!) where a bunch of the friendliest people you'll ever run into will be happy to help you out!

When Kirupa isn’t busy writing about himself in 3rd person, he is practicing social distancing…even on his Twitter, Facebook, and LinkedIn profiles.

Hit Subscribe to get cool tips, tricks, selfies, and more personally hand-delivered to your inbox.

COMMENTS

Serving you freshly baked content since 1998!
Killer hosting by (mt) mediatemple

Twitter Youtube Facebook Pinterest Instagram Github