Using Complex Data

So far we have learned about some simple, helpful data types: strings, numbers and booleans. We also learned about how to group bits of code together in functions.

Now, we are going to learn about two important data types: Objects and Arrays.

Objects Let Us Store Meta Data

An object is a special data type that can store other data about itself.

Here is an example of a user object that contains a first and last name:

const user = {
first: `Zac`,
last: `Gordon`,
}
// Logs "Zac"
console.log( user.first )
// Logs "Gordon"
console.log( user.last )

This is a new syntax for us. We have a variable named user then we see curly braces and another set of variables using colons instead of equal signs.

Notice that we have a coma between the values too. Without these colons and comas, we would get an error!

So if we tried this:

const userEqualSign = {
first= `Zac`,
last: `Gordon`,
}
// We would get this error
"Uncaught SyntaxError: Invalid shorthand property initializer line 2"
const userNoComa = {
first: `Zac`
last: `Gordon`,
}
// Would give us the error
"Uncaught SyntaxError: Unexpected identifier line 10"

While that error is crazy technical, it does tell us the line number so we can look for these common mistakes.

But don't worry, you will get used to writing objects in this way since we use them a lot in JavaScript.

Object Properties Are Variables Inside Variables

Variables inside of an object are called properties. Notice how we don't use const or let when setting up properties in objects.

When we want to get values from an object, we use the dot syntax like user.first or user.last.

We do not usually log out an object directly. If we tried to just do this:

const user = {
first: `Zac`,
last: `Gordon`,
}
console.log( user );

We would see something like this in the console:

An example of how an object is logged in the console

So, usually we do not log out an object directly. We tend to log out or use properties from an object.

Here is another example of a user object:

const user = {
id: 1,
username: `zgordon`,
loggedIn: false,
}
console.log( `User ID: ${user.id}` )
console.log( `Username: ${user.username}` )
console.log( `Is user logged in? ${user.loggedIn}` )

The reason this example above is important is that it shows us that object properties can have any other data type as their value. We can even have objects in objects:

const user = {
id: 1,
name: {
first: `Zac`,
last: `Gordon`,
}
}
console.log( `Welcome ${user.name.first} ${user.name.last}!` )

Notice that if we want to get properties within properties we just continue to use the dot syntax like with user.name.last.

Because objects can store lots of data in an organized way, they are quite commonly used in JavaScript.

For example, compare the approach of only using variables to define a post versus using an object:

const postId = 1
const postSlug = `new-post`
const postTitle = `New Post`
const postExcerpt = `Lorem to the postum`
const post = {
id: 1,
slug: `new-post`,
title: `New Post`,
excerpt: `Lorem to the postum`,
}

The object option here is obviously a cleaner and better way to organize related pieces of data.

Object Methods Are Like Variables With Built in Functions

In addition to storing the data types we have looked at as properties, we can also save functions as properties. When we save a function as a property, we call it a method.

Here is an example of a object method:

const user = {
name: `Zac`,
render: function() {
console.log( `Hi! ${user.name}` )
},
}
// Logs "Hi Zac!"
user.render()

Notice that we can refer to another object property within a method.

We could also write a method that takes parameters like this:

const user = {
name: `Zac`,
render: function( greeting) {
console.log( `${greeting} ${user.name}!` )
},
}
// Logs "Hi Zac!"
user.render( "Zac" );

When we want to refer to a property within another property or method we can use the keyword this as a shortcut for the name of the object.

For example, these two examples will do the same thing:

const user = {
first: `Zac`,
last: `Gordon`,
full: `${user.first} ${user.last}`,
render: function() {
console.log( `${user.full}!` );
},
}
const userWithThis = {
first: `Zac`,
last: `Gordon`,
full: `${this.first} ${this.last}`,
render: function() {
console.log( `${this.full}!` )
},
}

The keyword this can be a little confusing in JavaScript since it means different things in different contexts. However, this is pretty simple with objects. this refers the name of the object.

Arrays Are Collections of Data

Arrays are collections of data. They can contain any of the other data types inside of them.

Here is are some examples of arrays:

const ids = [ 1, 2, 3, 4, 5 ]
const topics = [ "JavaScript", "Coding", "Learning" ]
const random = [ false, "word", 1, 8, { title: "Object" } ]

Here we can see some of the basics of arrays. The start and end with square brackets. Then there is a coma between each of the items in the array.

The simplest way to get information out of an array is to use bracket notion like this:

const names = [ "Zac", "Christie", "Matt" ]
// Logs "Zac"
console.log( names[0] )
// Logs "Christie"
console.log( names[1] )
// Logs "Matt"
console.log( names[2] )

Here we see something very important: Arrays are zero indexed. This means that to get the first item in array we use 0 and not 1.

We can also easily get the length of an array like this:

const results = [ 99, 74, 39, 18, 74, 12, 67, 100 ]
// Logs out 8
console.log( results.length )

Since JavaScript is zero indexed, meaning it starts counting a zero instead of at one, we can do a cool little trick to get the last item in any array:

const results = [ 99, 74, 39, 18, 74, 12, 67, 100 ]
// Logs out 100
console.log( restuls[ results.length - 1 ] )

Understand what's happening here?

  1. We set an array that is 8 items long.

  2. results[ SOMETHING] will give us an item from the results array

  3. If we do results[ restuls.length ]

  4. It would be the same as results[ 8 ] , which would give us an error

  5. Because, JavaScript is zero indexed, results[ 7 ] is actually the last item

  6. Which gives us restuls[ results.length - 1 ]

Now that may seem a little tricky, and honestly, JavaScript can be a little tricky. However, these next few tricks with arrays we will look at are pretty easy to understand and use. Plus they help us quite a bit when working with collections of data.

Some Cool Things Arrays Can Do

Remember, arrays are collections of data. When you're working with collections of data, some common things you need to do include the following:

  1. Add and remove items to and from the collection

  2. Sort and filter the collection based on certain conditions

  3. Pass each item in the collection into a function

Arrays come with a bunch of built in functions that let easily do things like this, plus a lot more!

Adding an Removing Items from a Collection

The simplest way to add and remove items from a collection is like this:

const moons = [ "new", "waxing", "full", "waning" ]
// Adds item to the end of the collection
moons.push( "blue" )
// Logs out [ "new", "waxing", "full", "waning", "blue" ]
console.log( moons )
// Removes last item in the collection
moons.pop()
// Logs out [ "new", "waxing", "full", "waning" ]
console.log( moons )

We can also get more specific about where we add and remove items to and from a collection. For now we will keep it simple with the most commonly used .push() and .pop().

Sorting and Filtering Collections

Some of the most common JavaScript manipulation you can do to a collection is sorting and filtering.

Sorting a list alphabetically is easy with .sort() and .reverse().

const names = [ "Zac", "Amma", "Anna", "Michael" ]
// Logs ["Amma", "Anna", "Michael", "Zac"]
console.log( names.sort() )
// Logs ["Zac", "Michael", "Anna", "Amma"]
console.log( names.reverse() )

Sorting numbers is slightly more complex and looks like this:

const numbers = [ 2, 3, 1 ]
// Logs 1, 2, 3
console.log( numbers.sort(( a, b ) => a - b ))
// Logs 3, 2, 1
console.log( numbers.sort(( a, b ) => b - a ))

We can also check to see if a collection includes an item with the easy to remember includes().

const range = [ 1, 7, 12, 9, 3 ]
// Logs true
console.log( range.includes[ 9 ] )
// Logs false
console.log( range.includes[ 8 ] )
const currencies = [ "USD", "EUR", "CRC" ]
// Logs true
console.log( currencies.includes( "CRC" ) )
// Logs false
console.log( currencies.includes( "BTC" ) )

Sometimes we want to take a collection and filter out only certain items from it.

That is slightly more complicated, but not hard. This is what it would look like to only get scores over a certain number.

const scores = [17, 59, 77, 90, 80, 75, 92, 100]
// Gets saves only scores over 59 to new collection
const passingScores = scores.filter( score => score > 59 )
// Logs [77, 90, 80, 75, 92, 100]
console.log( passingScores )

Because .filter() is a little more complicated than the other one's we've looked at, I want to break this down a little bit:

  1. First, filter is a function that gets called on every item in the collection scores.filter( score => score > 59 )

  2. Then we give each item in the function a name for reference, we use "score" but it could be anything scores.filter( score => score > 59 )

  3. Next comes the actual "filter." In this case we check to see if score is greater than 59 scores.filter( score => score > 59 )

  4. Finally, we return the scores that passed this collection into a new collection const passingScores = scores.filter( score => score > 59 )

Although this syntax may look a little confusing, we will get practice it more and get comfortable with it over time. We will also see this style of code (calling functions on collections) pretty often.

Here is another example of filtering results:

// A collection of posts
const posts = [
{ title: "About JavaScript!", category: "JS" },
{ title: "About Collections!", category: "JS" },
{ title: "Using a Code Editor!", category: "Tooling" },
]
// Filters just posts with a category of JS
const jsPosts = posts.filter( post => post.category == "JS" )
// Logs out a collection containing two posts
// [
// { title: "About JavaScript!", category: "JS" },
// { title: "About Collections!", category: "JS" },
// ]
console.log( jsPosts )

Filters can be very handy and we will use them whenever we need to narrow down a collection of data.

Doing Something to Each Item in a Collection

Included in our top three list of common types of things you will do with collections in JavaScript is calling a function on each item in a collection.

We may refer to this as "looping" or "iterating" or "doing something to each item," but really what we're doing is passing each item in the array into a function in order to cause some change or effect.

We do this using a function called .map().

Here is an example of how we can "map" over each item in a collection and log it to the page.

const nums = [ 1, 2, 3 ]
// Logs out 1 2 3
nums.map( num => {
console.log( num )
})

Here is another example of "mapping" over each item and logging it to the page:

const streets = [ "plum", "orchard", "opeara" ]
// Logs out "plum" "orchard" "opeara"
streets.map( street => {
console.log( street )
})

We could also do things besides log things to the console. Here is an example that checks if the word "DRAFT: " is included in a post title and removes it.

const titles = [
`DRAFT: Best Post`,
`DRAFT: New Post`,
`Old Postt`,
`First Post`
];
// Remove DRAFT: from title if exists
// Return new collection with results
const publishedTitles = titles.map( title => {
// Check if title includes draft
if ( title.includes( `DRAFT: ` ) ) {
// If title contains draft
// Get all the characters after "DRAFT :" (7)
const newTitle = title.slice( 7 )
// Return the new title
return newTitle
} else {
// If title does not contain draft
// Return the title unchanged
return title
}
} )
// Logs out ["Best Post", "New Post", "Old Postt", "First Post"]
console.log( publishedTitles )

This code is obviously a little more complicated than the last two examples, but the only new thing here is the use of an if statement to check if our title includes the words DRAFT: .

Next Steps