Understanding JavaScript Objects: A Comprehensive Guide

Understanding JavaScript Objects: A Comprehensive Guide

Welcome to Day 7 of our 30-day JavaScript and Node.js learning seriesIn the last article, we introduced you to the JavaScript Arrays. Today, we’ll dive deeper into one of the most crucial topics—JavaScript Objects.

Objects are a fundamental data type in JavaScript, serving as building blocks for creating complex applications. They are essentially collections of key-value pairs, where keys are called properties and values can be of any data type. Understanding objects is crucial for mastering JavaScript programming.

In this comprehensive guide, we’ll delve into the intricacies of objects. We’ll explore how to create, access, and modify them. We’ll also learn how to use them effectively.

Creating Objects

There are two primary ways to create objects in JavaScript:

  1. Object Literal Notation:
const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30,
    city: "New York",
    greet: function() {
        console.log("Hello, my name is " + this.firstName + " " + this.lastName);
    }
};

2. By Creating an Instance of Object Directly

const person = new Object();
person.firstName = "John";
person.lastName = "Doe";
person.age = 30;
person.city = "New York";

3. Constructor Functions:

function Person(firstName, lastName, age, city) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.city = city;
this.greet = function() {
console.log("Hello, my name is " + this.firstName + " " + this.lastName);
};
}

const person1 = new Person("Alice", "Smith", 25, "Los Angeles");

Choosing the Right Method

  • Object Literal Notation: Ideal for creating simple objects with a fixed structure.
  • Constructor Functions: Suitable for creating complex objects with multiple instances and inheritance.

Accessing and modifying Properties

Once an object is created, you can access, add, and modify its properties:

  • Accessing Properties:
console.log(person.firstName); // Output: John
console.log(person["lastName"]); // Output: Doe
  • Adding Properties:
person.occupation = "Developer";
  • Modifying Properties:
person.age = 31;

Object Methods

Objects can have methods, which are functions defined within the object. Methods are used to perform actions on the object’s data.

Built-in Methods

JavaScript provides several built-in methods for objects:

Object Manipulation Methods:

  • Object.assign(target, ...sources):
    • Copies own enumerable properties from one or more source objects to a target object.
    • Does not copy non-enumerable properties (properties set with enumerable: false using Object.defineProperty).
    • Overwrites existing properties in the target object with properties from sources, based on property names.
    • Returns the modified target object.
    • Example:
const person = { name: "John" };
const details = { age: 30, city: "New York" };
const combined = Object.assign(person, details); // combined: { name: "John", age: 30, city: "New York" }
  • Object.create(prototype[, propertiesObject]):
    • Creates a new object that uses the specified prototype object.
    • The prototype object is used for property lookup when properties are accessed on the newly created object.
    • Optionally, you can provide a second argument, propertiesObject, to define specific properties on the new object.
    • Example:
function Person(name) { this.name = name; }
const person1 = new Person("Alice"); // person1 inherits from Person.prototype
const person2 = Object.create(Person.prototype, { age: { value: 25, writable: true } }); // person2 inherits from Person.prototype with a custom "age" property

Property Definition and Access Methods:

  • Object.defineProperty(obj, prop, descriptor):
    • Defines a new property directly on an object (obj), or modifies an existing property.
    • Takes three arguments:
      • obj: The object to define the property on.
      • prop: The name of the property (string or symbol).
      • descriptor: An object that describes the property (with properties like valuewritableenumerableconfigurable).
    • Example:
const person = {};
Object.defineProperty(person, "name", { value: "John", writable: true, enumerable: true });
console.log(person.name); // Output: John
  • Object.defineProperties(obj, propertiesObject):
    • Defines multiple properties on an object at once.
    • Takes two arguments:
      • obj: The object to define the properties on.
      • propertiesObject: An object whose properties will be defined on the target object.
    • Example:
const person = {};
Object.defineProperties(person, {
  name: { value: "John", writable: true },
  age: { value: 30, writable: false }
});
console.log(person.name); // Output: John
person.age = 31; // Throws an error because "age" is not writable
  • Object.entries(obj):
  • Returns an array of key-value pairs from an object’s own enumerable properties.
  • Each element in the array is an array of [key, value].
  • Example:
const person = { name: "John", age: 30 };
const entries = Object.entries(person); // entries: [["name", "John"], ["age", 30]]
  • Object.freeze(obj):
    • Prevents modifications to an object’s existing properties (value, writable, configurable).
    • Attempts to modify a frozen object’s properties will throw a TypeError.
    • Frozen objects cannot be further modified.
    • Example:
const person = { name: "John" };
Object.freeze(person);
person.name = "Alice"; // Throws a TypeError because the object is frozen
  • Object.getOwnPropertyDescriptor(obj, prop):
    • Returns a property descriptor object for a specified property (prop) on an object (obj).
    • The descriptor object describes the property’s characteristics (value, writable, enumerable, configurable).
    • Example:
const person = { name: "John" };
const descriptor = Object.getOwnPropertyDescriptor(person, "name");
console.log(descriptor); // { value: "John", writable: true, enumerable: true, configurable: true }
  • Object.getOwnPropertyDescriptors(obj):
    • Returns an object containing all own property descriptors for an object.
    • Similar to Object.getOwnPropertyDescriptor but returns all properties at once.
    • Example:
const person = { name: "John", age: 30 };
const descriptors = Object.getOwnPropertyDescriptors(person);
console.log(descriptors); // { name: { ... }, age: { ... } } (details of each property descriptor)
  • Object.getOwnPropertyNames(obj):
    • Returns an array of all own property names (strings) of an object.
    • Only enumerable properties are included.
    • Example:
const person = { name: "John", age: 30, _secret: "" }; // _secret is not enumerable by default
const propertyNames = Object.getOwnPropertyNames(person); // propertyNames: ["name", "age"]
  • Object.getOwnPropertySymbols(obj):
    • Returns an array of all own property names (symbols) of an object.
    • Only enumerable properties are included.
    • Example:
const person = { name: "John", age: 30, [Symbol.for("secret")]: "" }; // Symbol property
const propertySymbols = Object.getOwnPropertySymbols(person); // propertySymbols: [Symbol(secret)]
  • Object.getPrototypeOf(obj):
    • Returns the object’s prototype (the object that the current object inherits from).
    • If the object has no prototype (e.g., Object.create(null)), it returns null.
    • Example:
function Person() {}
const person1 = new Person();
console.log(Object.getPrototypeOf(person1)); // Output: Person.prototype
  • Object.is(value1, value2):
    • Determines if two values are exactly the same.
    • Handles special cases like NaN0, and -0 more reliably than ==.Example
  • Object.isExtensible(obj):
    • Checks if an object can be extended (new properties can be added).
    • Returns true if the object is extensible, false otherwise.
    • Example:
const person = {};
console.log(Object.isExtensible(person)); // Output: true
Object.preventExtensions(person);
console.log(Object.isExtensible(person)); // Output: false
  • Object.isFrozen(obj):
    • Checks if an object is frozen (no modifications are allowed).
    • Returns true if the object is frozen, false otherwise.
    • Example:
const person = {};
Object.freeze(person);
console.log(Object.isFrozen(person)); // Output: true
  • Object.isSealed(obj):
    • Checks if an object is sealed (no new properties can be added, but existing properties can be modified).
    • Returns true if the object is sealed, false otherwise.
    • Example:
const person = {};
Object.seal(person);
console.log(Object.isSealed(person)); // Output: true
  • Object.keys(obj):
    • Returns an array of an object’s own enumerable property names (strings).
    • Example:
const person = { name: "John", age: 30 };
const keys = Object.keys(person); // keys: ["name", "age"]
  • Object.preventExtensions(obj):
    • Prevents new properties from being added to an object.
    • Existing properties can still be modified.
    • Example:
const person = {};
Object.preventExtensions(person);
person.city = "New York"; // Throws a TypeError
  • Object.seal(obj):
    • Prevents both new properties from being added and existing properties as non-configurable.
    • Similar to Object.freeze but allows existing properties to be modified.
    • Example:
const person = {
    name: "Clara"
};
Object.seal(person);
person.city = "New York"; // Throws a TypeError
person.name = "Alice"; // Allowed (existing property can be modified)
delete person.city; // Throws a TypeError
  • Object.setPrototypeOf(obj, proto):
    • Sets the prototype of an object.
    • Replaces the existing prototype with the specified proto object.
    • Example:
const person = {};
const personPrototype = { greet: function() { console.log("Hello!"); } };
Object.setPrototypeOf(person, personPrototype);
person.greet(); // Output: Hello!
  • Object.values(obj):
    • Returns an array of an object’s own enumerable property values.
    • Example:
const person = { name: "John", age: 30 };
const values = Object.values(person); // values: ["John", 30]

Custom Methods

You can also define your own custom methods on objects:

const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30,
    greet: function() {
        console.log("Hello, my name is " + this.firstName + " " + this.lastName);
    },
    getFullName: function() {
        return this.firstName + " " + this.lastName;
    }
};

Nested Objects

Objects can be nested within other objects:

const address = {
    street: "123 Main St",
    city: "New York",
    zipCode: "10001"
};

const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30,
    address: address
};

Arrays as Properties

Objects can have arrays as properties:

const person = {
    firstName: "John",
    lastName: "Doe",
    hobbies: ["reading", "hiking", "programming"]
};

Object Prototypes

In JavaScript, objects inherit properties and methods from their prototype. The prototype chain allows objects to access properties and methods defined on their prototype and its parent prototypes.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

Person.prototype.greet = function() {
    console.log("Hello, my name is " + this.firstName + " " + this.lastName);
};

const person1 = new Person("Alice", "Smith");
person1.greet(); // Output: Hello, my name is Alice Smith

When to Use Prototypes

Prototypes are useful for creating reusable code and implementing inheritance. They can be especially helpful when you need to define common properties and methods for multiple objects.

Object Copying and Cloning

When you assign one object to another, both variables will reference the same object in memory. This means that any changes made to one object will also be reflected in the other.

To create a true copy of an object, you can use the Object.assign() method or the spread operator:

const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30
};

// Using Object.assign()
const personCopy = Object.assign({}, person);

// Using the spread operator
const personCopy2 = { ...person };

Now, personCopy and personCopy2 are independent copies of the original person object. Changes made to one copy will not affect the other.

Conclusion

Objects are a fundamental data type in JavaScript, providing a flexible and powerful way to represent data and encapsulate behavior. By understanding how to create, manipulate, and use objects effectively, you can build robust and scalable JavaScript applications.

In our next post we will explore ES6+ Features in JavaScript.


Previous Lesson

Day 6: Javascript Arrays

Next Lesson

Day 8: ES6+ Features in JavaScript


Share with your friends


3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *