Enhanced Object Literals

ES6 (ECMAScript 2015) introduced several shorthand improvements to how you write objects in JavaScript. These are called enhanced object literals. They make your code cleaner and less repetitive when creating objects.

The three main enhancements are: property shorthand, method shorthand, and computed property names.

When a variable name and the object property name are exactly the same, you do not need to repeat yourself. You can just write the variable name once.

javascript

let name = "Alice";
let age = 25;

// Old way
let user1 = { name: name, age: age };

// ES6 shorthand (same name, write once)
let user2 = { name, age };

console.log(user2); // Output: { name: 'Alice', age: 25 }

This is especially handy when building objects from function parameters or variables that already have the right names.

When adding a function to an object, you no longer need the function keyword. You can write the method name and parentheses directly.

javascript

// Old way
let calculator1 = {
  add: function(a, b) {
    return a + b;
  }
};

// ES6 method shorthand
let calculator2 = {
  add(a, b) {
    return a + b;
  }
};

console.log(calculator2.add(3, 4)); // Output: 7

The method shorthand keeps the object cleaner. It works exactly the same as using the function keyword inside an object.

With ES6, you can use an expression inside square brackets [] to set a property name dynamically when creating an object.

javascript

let key = "color";

let car = {
  brand: "Toyota",
  [key]: "red"   // computed property name
};

console.log(car); // Output: { brand: 'Toyota', color: 'red' }

You can also use expressions inside the brackets:

javascript

let prefix = "item";

let list = {
  [prefix + "1"]: "Apple",
  [prefix + "2"]: "Banana"
};

console.log(list); // Output: { item1: 'Apple', item2: 'Banana' }

Optional chaining (?.) lets you safely access deeply nested properties without throwing an error if something in the chain is null or undefined. Instead of an error, it simply returns undefined.

javascript

let user = {
  name: "Alice",
  address: {
    city: "London"
  }
};

// Without optional chaining (can throw error)
console.log(user.address.city);      // Output: London
console.log(user.phone.number);      // TypeError: Cannot read properties of undefined

// With optional chaining (safe)
console.log(user.address?.city);     // Output: London
console.log(user.phone?.number);     // Output: undefined (no error)

Optional chaining works well inside if conditions when you need to check multiple levels of an object before using a value.

javascript

let order = {
  customer: {
    name: "Bob",
    contact: null
  }
};

// Old way (verbose)
if (order && order.customer && order.customer.contact && order.customer.contact.email) {
  console.log(order.customer.contact.email);
}

// With optional chaining (clean)
if (order?.customer?.contact?.email) {
  console.log(order.customer.contact.email);
} else {
  console.log("No email found"); // Output: No email found
}

Optional chaining combined with the nullish coalescing operator ?? is a powerful pattern. You can safely read a value and provide a fallback if it is null or undefined.

javascript

let settings = {
  theme: null
};

let theme = settings?.theme ?? "light";
console.log(theme); // Output: light

let fontSize = settings?.font?.size ?? 16;
console.log(fontSize); // Output: 16

This pattern is very common when working with API responses or user settings where values might be missing.

You can use optional chaining to call a method only if it exists on an object. This prevents errors when the method might not be available.

javascript

let player = {
  name: "Alex",
  greet() {
    return "Hello, I am " + this.name;
  }
};

let robot = {
  name: "R2D2"
  // no greet method
};

console.log(player.greet?.());  // Output: Hello, I am Alex
console.log(robot.greet?.());   // Output: undefined (no error)

The ?.() syntax checks that the method exists before calling it. Without this, calling a non-existent method would throw a TypeError.

Optional chaining also works with arrays. You can safely access array elements or call array methods without worrying if the array exists.

javascript

let data = {
  items: ["apple", "banana"]
};

let emptyData = {};

// Safely access first item
console.log(data.items?.[0]);       // Output: apple
console.log(emptyData.items?.[0]);  // Output: undefined (no error)

// Check if array has items
let hasItems = data.items?.length > 0;
console.log(hasItems); // Output: true

let hasItems2 = emptyData.items?.length > 0;
console.log(hasItems2); // Output: false (undefined > 0 is false)

This is very useful when working with data from an API that might or might not include arrays.

  • Property shorthand — when the variable name matches the property name, write it once: { name } instead of { name: name }.
  • Method shorthand — skip the function keyword inside objects: greet() {} instead of greet: function() {}.
  • Computed property names — use square brackets to set property names from expressions: { [key]: value }.
  • Optional chaining (?.) — safely read nested properties and call methods without errors when values might be null or undefined.
  • Combine ?. with ?? to read optional values and provide a fallback.
  • Use ?.() to call a method only if it exists on an object.
  • Use ?.[index] to safely access array elements.