Mastering JavaScript Objects: A Comprehensive Guide

1. Introduction to JavaScript objects

In JavaScript, an object is a powerful data type that allows us to store and organize multiple values as key-value pairs.

Objects provide a way to group together related data properties and methods (functions) into a single entity, making it easier to manage and manipulate complex data structures.

With objects, we can create custom data types tailored to our specific needs and use them to model real-world concepts in our code.

2. Creating new objects

In JavaScript, there are several ways to create new objects. The object literal is the most common and straightforward way to create new objects. The object literal is also known as the object initializer.

The syntax to declare an object using object literal is:

const object_name {
    key1: value1,
    key2: value2
};

In this approach, we create an object by enclosing its properties with curly braces {}. Each property is specified as a key:value pair separated by a colon (:). The key is a string (or Symbol)  that acts as an identifier, and the value can be of any valid JavaScript datatype, such as string, number, boolean, array, or even another object.

For example:

const student = {
    name: "Justin",
    class: 12
};

3. JavaScript object properties

In JavaScript, properties in objects are an association between keys (or names) and values.

For example:

const person = {
    name: "James Bond",
    age: 37
};

In this example, we create an object person with two properties: name and age. The name property is set to the string "James Bond", while the age property is set to the number 37.

4. Accessing Object Properties

There are two main ways to access object properties in JavaScript.

Using dot notation

We use the dot (.) followed by the property name to access the property of an object.

The syntax of the dot notation is:

objectName.propertyName;

This is the simpler and more common way to access the properties of an object.

For example:

const person = {
    name: "James Bond",
    age: 37
};

console.log(person.name);  // James Bond

console.log(person.age);  // 37

Using bracket notation

We use a square bracket ([]) with the property name inside to access the property of an object.

The syntax of bracket notation is:

objectName["propertyName"];

This method is useful when the property name is stored in a variable or contains special characters or spaces.

For example:

const person = {
    "first name": "James",
    age: 37
};

// Accessing a property with a space character using bracket notation

console.log(person["first name"]); // Output: James

// Accessing a property with property name stored in a variable

let propertyName = "age";

console.log(person[propertyName]); // Output: 37

It is generally not considered a good practice to use spaces in the property names of an object in JavaScript.

5. Modifying the value of a property

In JavaScript, we can modify the value of an object property by using either dot notation or bracket notation.

For example:

// Define an object with a property "name"
const person = {
    name: "James Bond"
};

// Modify the value of the "name" property using dot notation
person.name = "Ethan Hunt";
console.log(person.name); // Output:Ethan Hunt

// Modify the value of the "name" property using bracket notation
person["name"] = "Tony Stark";
console.log(person.name); // Output: Tony Stark

In the example above, we first define an object person with a property name and set its value to "James Bond". We then use dot notation (person.name) to modify the value of the name property to "Ethan Hunt". We can also use bracket notation (person["name"]) to modify the value of the name property to "Tony Stark".

6. Adding a new property to an object

We can add a new property to an object at any time after its creation using either dot or bracket notation. 

For example:

// Define an object with a property "name"
const person = {
    name: "James Bond"
};


// Adding a new property "age" to an object using dot notation
person.age = 37;

// Adding a new property "country" to an object using bracket notation
person["country"] = "United Kingdom";

// Log the person object to the console
console.log(person); 
// Output: {name: 'James Bond', age: 37, country: 'United Kingdom'}

In the example above, we create an object person with a property name and set its value to "James Bond". We then use dot notation (person.age) to add a new property age with value 37 to the object person. We can also add a new property country with the value "United Kingdom" to the object person using bracket notation (person["country"]).

7. Deleting a property of an object

We can delete a property of an object using a delete operator.

The general syntax to delete a property of an object is:

delete objectName.propertyName;

Here’s an example:

const person = {
    name: "James Bond",
    age: 37
};

delete person.age;

console.log(person.age);  // undefined

In the example above, we use the delete operator to remove the age property from the person object.

If we try to access a property that has been deleted from an object, JavaScript will return undefined.

It is generally recommended to avoid deleting properties from objects, as it can lead to unexpected behavior and potential performance issues. Instead, consider setting the property value to null or undefined if you want to signify the absence of value.

8. Checking if a property already exists

It is a good practice to check if a property already exists before trying to access or modify it. This helps prevent errors and unexpected behavior in our code.

We can check if a property exists in an object using the hasOwnProperty() method or by using the in operator. Here’s how to do it:

Using the hasOwnProperty() method

The hasOwnProperty() is a more specific way to check if an object has a property. It checks if the property is directly defined on the object and not inherited from its prototype chain.

This is particularly useful when we want to ensure that the property we are checking for belongs to the object itself and not to any of its parent prototypes.

For example:

const person = {
    name: "James Bond",
    age: 37
};

// Checking if an object 'person' has an 'age' property using the 'hasOwnProperty()' method
if(person.hasOwnProperty("age")) {
    console.log("'person' has the 'age' property");
} else {
    console.log("'person' doesn't have the 'age' property");
}

// Output: 'person' has the 'age' property

// Creating a new object "personOne" with "person" as its prototype
const personOne = Object.create(person);


// Checking if an object 'personOne' has an 'age' property using the "hasOwnProperty()" method
if(personOne.hasOwnProperty("age")) {
    console.log("'personOne' has the 'age' property");
} else {
    console.log("'personOne' doen't have the 'age' property");
}

// Output: 'personOne' doesn't have the 'age' property

In the example above, we create an object person with properties name and age.

We then use the hasOwnProperty() method to check if the person object has the age property defined on it. Since the age property is directly defined on the person object, person.hasOwnProperty("age") returns true

Next, we create a new object personOne with person as its prototype using Object.create(person). This means that the personOne inherits the properties of the person object.

However, since the age property is not directly defined on the personOne object, but rather inherited from its prototype, personOne.hasOwnProperty("age") returns false

This demonstrates how the hasOwnProperty() method can be used to distinguish between properties that are directly defined on an object and those that are inherited from its prototype chain.

Using the “in” operator

The in operator checks whether a property exists in an object, including properties inherited from its prototype chain.

This is useful when we are less concerned about the source of the property and simply want to determine its presence.

For example:

const person = {
    name: "James Bond",
    age: 37
};

// Checking if an object 'person' has an 'age' property using the 'in' operator
if('age' in person) {
    console.log("'person' has the 'age' property");
} else {
    console.log("'person' doesn't have the 'age' property");
}

// Output: 'person' has the 'age' property

// Creating a new object "personOne" with "person" as its prototype
const personOne = Object.create(person);


// Checking if an object 'personOne' has an 'age' property using the 'in' operator
if('age' in personOne) {
    console.log("'personOne' has the 'age' property");
} else {
    console.log("'personOne' doen't have the 'age' property");
}

// Output: 'personOne' has the 'age' property

In the example above, we create an object person with two properties name and age.

We then check if the person object has an age property using the in operator. Since the person object does have an age property,  'age' in person returns true.

Next, we create a new object personOne using the Object.create(person), with person as its prototype. This means the personOne inherits the properties of the person object. 

We then check if the personOne object has an age property using the in operator. Since the personOne inherits all the properties of its prototype, which includes the age property, the statement 'age' in personOne returns true

9. JavaScript object methods

In JavaScript, objects can store not only data but also functions. These functions, when assigned as properties of an object, are called methods. Methods allow us to define behavior for objects and interact with their data.

For example:

const person = {
    firstName: "James",
    lastName: "Bond",

    getFullName: function() {
        return this.firstName + " " + this.lastName;
    }
};

console.log(person.getFullName());  // Output: James Bond

In the example above, we create an object with three properties: name, age, and getFullName.

The getFullName property is a method that returns the full name of the person by concatenating their first and last names with a space in between. This method uses the this keyword to access the values of the firstName and lastName properties of the person object.

We can then call the getFullName method on the person object using the dot notation like this:

 person.getFullName();

The this keyword refers to the current object context, which is the object on which the method is called. It allows the method to access and work with the properties and methods of the object to which it belongs. 

10. Nested objects

An object in JavaScript can contain another object as one of its properties. This concept is called “nested objects”. This allows us to create more complex and organized data structures.

Here’s an example of nested objects:

const person = {
    name: "James Bond",
    age: 37,
    address: {
        street: "30 Wellington Square",
        city: "London",
        country: "United Kingdom"
    }
};

// Accessing nested object properties
console.log(person.address.street);
console.log(person.address.city);

In the example above, we create an object person with three properties: name, age, and address.

The address property is an object itself with three properties: street, city, and country. This is an example of a nested object, where an object is defined as the property of another object.