Lesson Weekend

As mentioned in the last lesson, a real world application would use a database. In a database, each individual Contact would have a unique ID. This allows us to identify records by a unique ID instead of something like their last name, which isn't guaranteed to be unique. Right now, we are identifying each of our Contacts by their firstName property. However, there are multiple problems with that approach. An ID needs to be unique - but what if you have two Contacts that each have the same firstName property? In our case, it would be better if each Contact has a numerical ID - and we'll want to ensure that each ID is different - just like in a real database.

Unique Object IDs

Let's update our code so each Contact is assigned an ID as soon as it's created.

We'll update several functions to make this work. First, let's update the AddressBook constructor to instantiate new AddressBooks with a currentId property:

scripts.js
// Business Logic for AddressBook ---------
function AddressBook() {
  this.contacts = {};
  this.currentId = 0;
}

...

Now each time a new AddressBook is created, it will have a currentId property that begins at 0. What is the point of doing this? Well, our IDs are going to increase sequentially. But how does our AddressBook know the lowest available ID that hasn't been used yet? It would be terribly inefficient to have to look through all the stored Contacts to see which IDs aren't being used - and it wouldn't even be effective because it wouldn't account for the IDs of deleted Contacts. In a real-world database, an ID is never reused - even if the Contact or other entry it's referring to is deleted.

We'll be able to use this.currentId to ensure each new Contact added to the AddressBook has a unique ID. We'll do this by defining another prototype called assignId():

scripts.js
// Business Logic for AddressBook ---------

...

AddressBook.prototype.assignId = function() {
  this.currentId += 1;
  return this.currentId;
};

...

This new method will increment the this.currentId property on the AddressBook object by 1 and return the updated value. This mimics a database by creating sequentially incrementing ID values which are never repeated so they are always unique.

Finally, we need to call this new assignId() method whenever we add a new Contact to the AddressBook. We already have a method called addContact() that adds contacts to our mock database. We just need to update it to use our new sequential IDs as keys instead of using the firstName property.

scripts.js
// Business Logic for AddressBook ---------

...

AddressBook.prototype.addContact = function(contact) {
  contact.id = this.assignId();
  this.contacts[contact.id] = contact;
};

...

Let's take a closer look at the updates here.

When we call AddressBook.prototype.addContact(contact), we are passing in a Contact object that has a firstName, lastName, and phoneNumber. It doesn't have an id property yet.

The first thing we do is call our new AddressBook.prototype.assignId() method on this object. AddressBook.prototype.assignId() will increment this.currentId by 1 and then assign that value to the Contact object we are passing into AddressBook.prototype.addContact().

Technically, we don't need a separate method for assigning IDs - but it's always a good idea to keep our code separate. The AddressBook.prototype.assignId() has only one job - figure out the next sequential ID and return it. It doesn't need to know anything about contacts. If we later decided to use a different system for assigning IDs, we'd only need to change the code in one place.

Another important thing to emphasize is that we can add new properties to an object whenever we want. It doesn't have to happen in an object's constructor. For instance, there's no mention of an id property in the Contact constructor. We could technically do something like this in the Contact constructor - this.id = undefined. It's not very clean, though, and it's completely unnecessary to do so. Instead, we can easily add this new property later - and that's exactly what we do in the AddressBook.prototype.addContact() function.

Finally, we're also using a Contact's new id property as a key when we add the Contact to AddressBook:

this.contacts[contact.id] = contact;

In this line of code, this refers to the AddressBook we've created. Our instance of AddressBook has a contacts property which itself contains an object that stores the key-value pairs of all our Contacts. In the line of code above, we are creating a key in the contacts object which corresponds to the new Contacts ID. The value associated with the key is the Contact object itself.

This is a big improvement over using the firstName property as a key.

So to recap, we now have a method that automatically assigns a sequential ID to a new Contact object. Once that ID is assigned, the Contact is added to the contacts mock database via a key-value pair where the key is equal to the Contact's ID and the value is the Contact object itself.

The updated scripts.js file should now look like this:

scripts.js
// Business Logic for AddressBook ---------
function AddressBook() {
  this.contacts = {};
  this.currentId = 0;
}

AddressBook.prototype.addContact = function(contact) {
  contact.id = this.assignId();
  this.contacts[contact.id] = contact;
};

AddressBook.prototype.assignId = function() {
  this.currentId += 1;
  return this.currentId;
};

// Business Logic for Contacts ---------
function Contact(firstName, lastName, phoneNumber) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.phoneNumber = phoneNumber;
}

Contact.prototype.fullName = function() {
  return this.firstName + " " + this.lastName;
};

We can now create a Contact and add it to our AddressBook mock database. When we do so, it will have a unique ID. It doesn't have the complexity or efficiency of a real database, but soon we'll be able to use our AddressBook to retrieve specific contacts just as we would with an actual database.


Example GitHub Repo for the Address Book

Example


Here's how scripts.js will look by the end of the lesson:

scripts.js
// Business Logic for AddressBook ---------
function AddressBook() {
  this.contacts = {};
}

AddressBook.prototype.addContact = function(contact) {
  contact.id = this.assignId();
  this.contacts[contact.id] = contact;
};

AddressBook.prototype.assignId = function() {
  this.currentId += 1;
  return this.currentId;
};

// Business Logic for Contacts ---------
function Contact(firstName, lastName, phoneNumber) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.phoneNumber = phoneNumber;
}

Contact.prototype.fullName = function() {
  return this.firstName + " " + this.lastName;
};

Example GitHub Repo for the Address Book

Lesson 9 of 23
Last updated October 12, 2021