Objects Basics

Difficulty: Beginner

Objects are the most fundamental data structure in JavaScript - nearly everything in the language is an object or behaves like one. An object is an unordered collection of key-value pairs, where keys are strings (or Symbols) and values can be any type, including other objects, arrays, and functions. Objects are used to group related data and behavior together, forming the backbone of JavaScript programs.

The most common way to create an object is the object literal syntax: const person = { name: "Alice", age: 25 }. You can also create objects using the Object constructor (new Object()), Object.create() for prototype-based creation, or constructor functions and classes, which you'll learn about in later lessons. The literal syntax is by far the most popular for its simplicity and readability.

You access object properties using dot notation (person.name) or bracket notation (person["name"]). Dot notation is cleaner and preferred for static property names. Bracket notation is required when the property name is stored in a variable, contains special characters, or starts with a number. You modify properties by assigning new values and add new properties simply by assigning to a name that doesn't exist yet. The delete operator removes properties entirely.

ES6 introduced several shorthand syntaxes that make working with objects more concise. Property shorthand lets you write { name } instead of { name: name } when the variable name matches the property name. Method shorthand lets you write { greet() {} } instead of { greet: function() {} }. Computed property names let you use expressions as property keys: { [expression]: value }. These shorthands are ubiquitous in modern JavaScript and React code.

When a function is stored as an object property, it's called a method. Inside a method, the this keyword refers to the object the method was called on. This allows methods to access and modify the object's own properties. However, this is one of JavaScript's trickiest concepts - its value depends on how the function is called, not where it's defined. Arrow functions don't have their own this, making them unsuitable as object methods but perfect for callbacks within methods.

The Object class provides several static methods for working with objects. Object.keys() returns an array of an object's own enumerable property names. Object.values() returns an array of values. Object.entries() returns an array of [key, value] pairs, which is perfect for iteration with for...of or destructuring. Object.assign() copies properties from source objects to a target object. These methods, combined with the for...in loop, give you powerful tools for inspecting and transforming objects.

Code examples

Creating and Accessing Objects

// Object literal
const person = {
  name: "Alice",
  age: 25,
  city: "New York",
  isStudent: true
};

// Dot notation (preferred for known keys)
console.log(person.name);       // "Alice"
console.log(person.age);        // 25

// Bracket notation (required for dynamic keys)
const key = "city";
console.log(person[key]);       // "New York"
console.log(person["isStudent"]); // true

// Modifying properties
person.age = 26;
person.email = "alice@example.com"; // Add new property
console.log(person);

// Deleting properties
delete person.isStudent;
console.log("isStudent" in person); // false

// Checking if property exists
console.log("name" in person);     // true
console.log(person.hasOwnProperty("email")); // true
console.log(person.phone);         // undefined (not an error)

Use dot notation for known property names and bracket notation for dynamic keys. The 'in' operator checks for property existence (including inherited properties). hasOwnProperty checks only the object's own properties. Accessing a nonexistent property returns undefined without throwing an error.

ES6 Shorthand Syntax

// Property shorthand
const name = "Bob";
const age = 30;
const city = "Chicago";

const user = { name, age, city };
// Equivalent to: { name: name, age: age, city: city }
console.log(user);

// Method shorthand
const calculator = {
  value: 0,
  add(n) {          // Shorthand for add: function(n)
    this.value += n;
    return this;     // Enable chaining
  },
  subtract(n) {
    this.value -= n;
    return this;
  },
  result() {
    return this.value;
  }
};

calculator.add(10).add(5).subtract(3);
console.log(calculator.result()); // 12

// Computed property names
const field = "score";
const dynamicObj = {
  [field]: 95,
  [`${field}Label`]: "Test Score",
  [`get${field[0].toUpperCase() + field.slice(1)}`]() {
    return this[field];
  }
};
console.log(dynamicObj);
console.log(dynamicObj.getScore());

Property shorthand eliminates redundancy when variable names match property names. Method shorthand provides cleaner syntax for object methods. Computed property names (using [expression]) allow dynamic key creation - very useful when building objects programmatically.

The this Keyword in Methods

const user = {
  name: "Alice",
  greetings: ["Hi", "Hello", "Hey"],

  // Regular method - 'this' refers to the object
  introduce() {
    console.log(`I'm ${this.name}`);
  },

  // Arrow functions DON'T have their own 'this'
  // They inherit 'this' from the enclosing scope
  listGreetings() {
    // Arrow function here correctly uses 'this' from listGreetings
    this.greetings.forEach(g => {
      console.log(`${g}, ${this.name}!`);
    });
  }
};

user.introduce();
user.listGreetings();

// Careful: extracting a method loses 'this'
const fn = user.introduce;
// fn(); // Would log: "I'm undefined" (this is now global/undefined)

// Fix: bind the method
const boundFn = user.introduce.bind(user);
boundFn(); // Works correctly

In methods, 'this' refers to the object the method is called on. Arrow functions inside methods correctly inherit 'this' from the method scope, making them perfect for callbacks like forEach. Extracting a method from an object loses the 'this' binding - use .bind() to fix it.

Object.keys, Object.values, Object.entries

const product = {
  name: "Laptop",
  price: 999,
  brand: "TechCo",
  inStock: true
};

// Object.keys - array of property names
console.log(Object.keys(product));

// Object.values - array of values
console.log(Object.values(product));

// Object.entries - array of [key, value] pairs
console.log(Object.entries(product));

// Iterating with for...in
console.log("\nfor...in loop:");
for (const key in product) {
  console.log(`  ${key}: ${product[key]}`);
}

// Iterating with Object.entries + destructuring
console.log("\nObject.entries + destructuring:");
for (const [key, value] of Object.entries(product)) {
  console.log(`  ${key} => ${value}`);
}

// Practical: object to query string
const params = { search: "javascript", page: 1, limit: 10 };
const queryString = Object.entries(params)
  .map(([key, val]) => `${key}=${val}`)
  .join("&");
console.log(`?${queryString}`);

Object.keys/values/entries return arrays, making objects compatible with array methods like map, filter, and reduce. Object.entries combined with destructuring is the most powerful iteration pattern - it gives you both the key and value in a clean syntax.

Key points

Concepts covered

Object Literals, Property Access, Object Methods, this Keyword, Computed Properties, Object.keys/values/entries