JavaScript (ES5) Objects
Tags: javascript, beginners
Published: 2018-11-27 18:44:53

_This was originally posted on my site at https://martyhimmel.me on January 31, 2017. Like a number of others on dev.to, I've decided to move my technical blog posts to this site._

While discussing data types, we compared an object to a dictionary - a set of terms (properties or keys) and their definitions (values). Another way to think of an object is as a container for something. Here's an example:

```js
var person = {
  firstName: 'John',
  lastName: 'Smith',
  age: 24,
  isMarried: true,
  children: ['Jack', 'Judy'],
  pet: {
    type: 'dog',
    name: 'Fido'
  }
};
```

In this example, the `person` object contains several different data types, including another object. Accessing each of those properties is done with dot notation.

```js
console.log(person.firstName); // John
console.log(person.age); // 24
console.log(person.children[0]); // Jack
console.log(person.pet.name); // Fido
```

Objects can also contain functions. Here's an example, continuing with the `person` object:

```js
var person = {
  firstName: 'John',
  lastName: 'Smith',
  ... // The other properties
  getFullName: function() {
    return person.firstName + ' ' + person.lastName;
  }
};
console.log(person.getFullName()); // John Smith
```

Just like the other properties of an object, you declare the property name and give it a value. In this case, the value is a function.

## `this`

The `getFullName` function could be written in a slightly different way, using the `this` keyword.

```js
var person = {
  ...
  getFullName: function() {
    return this.firstName + ' ' + this.lastName;
  }
}
console.log(person.getFullName()); // John Smith
```

The result is the same. `this` is a reference to the current object. I'll save the details of how `this` works for a separate tutorial, as it can be a bit confusing until you understand all the rules for it. For this tutorial, we'll keep it simple though, and `this` will always refer to the current/containing object.

## Creating Objects with Constructor Functions

Up to this point, we've been manually creating every object. That's fine, but it makes for a lot of repetitious code. If we wanted 10 `person` objects, we'd have to create 10 separate objects.

```js
var person1 = {
  firstName: 'John',
  lastName: 'Smith'
};
var person2 = {
  firstName: 'Jane',
  lastName: 'Doe'
};
// and so on
```

There's a principle in programming called "DRY" - Don't Repeat Yourself. If you can avoid duplicating code (sometimes, you can't or don't necessarily want to), it makes the code easier to maintain. So, how do we use that principle here?

You'll notice each of our `person` objects have the same properties - `firstName` and `lastName`. They could have all the properties from the first example, if we wanted, but we'll keep it simple here. In any case, the same code is repeated in creating every object.

This is where constructor functions come in handy. A constructor function is a function that produces objects. A common naming convention is to capitalize the first letter of a constructor function. This sets it apart from other functions. Otherwise, a constructor function is created in exactly the same way as any other function. Now, let's convert the above example.

```js
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
var person1 = new Person('John', 'Smith');
var person2 = new Person('Jane', 'Doe');
// and so on
console.log(person1.firstName + ' ' + person1.lastName); // John Smith
console.log(person2.firstName + ' ' + person2.lastName); // Jane Doe
```

Using the `Person` constructor gets rid of the repititious code of assigning the first and last name to each object. Imagine if each person had 10 or 15 properties. That would be a lot of repeated code. Now imagine you had 500 people, then found a bug or needed to change some property or method of the object. You'd have to make 500 changes. Using a constructor function, you only have to change it in one place. This is why the DRY principle is important.

The `Person` constructor takes two arguments - `firstName` and `lastName`. The use of `this` inside the function is used to assign the values passed to the given property name. In other words, the `firstName` argument passed to the constructor is assigned to the `firstName` (`this.firstName`) property of the created object.

Calling `new` is what creates the actual object. If we look at the `person1` object that was created, it looks like this:

```js
console.log(person1); // {firstName: 'John', lastName: 'Doe'}
```

## Object Prototypes

In this section, we'll continue using the above `Person` constructor as our base. It would be convenient to have a `getFullName` method - like in the first section. That's where prototypes come in.

JavaScript is a prototype based language. You can read about it in depth in [Mozilla's developer docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain).

Every object in JavaScript has a prototype. Logging an object to the console gives more info than just the object itself. So, a real view of `console.log(person1);` would give us this (using Chrome):

```js
Person
  firstName: "John"
  lastName: "Smith"
  __proto__: Object
    constructor: Person(firstName, lastName)
      // a handful of other properties
      prototype: Object
        // more properties
    __proto__: Object
      // a bunch of properties inherited from the prototype chain
```

As you can see, there's a whole lot more going on than just the two properties we created in the constructor. That's all part of the prototype structure of JavaScript objects. The prototype allows objects to inherit properties from other objects. This also means we can retrofit objects with new methods by tapping into the `prototype` property of the constructor.

The format for adding methods via the prototype chain is:

```
[constructor name].prototype.[method name] = function() {
    // do something
};
```

Let's add the `getFullName` method.

```js
Person.prototype.getFullName = function() {
  return this.firstName + ' ' + this.lastName;
};
console.log(person1.getFullName()); // John Smith
```

Now that the `Person` constructor has a `getFullName` method, that method is available to every instance - `person1`, `person2`, and any other objects that may have been created with the constructor. And because of the way prototypes work, even if a `Person` object was created before the prototype method was added to the constructor (as is the case in this example - write the constructor, create two objects, add the prototype method), that method is still available to _all_ objects created with the given constructor.