JavaScript Enhanced Object Literals

Why should you care about Enhanced Object Literals?

These features remove repetitive object code and make your intent clearer. You will use them regularly when building configs, API payloads, and reusable components.

ES6 (ECMAScript 2015) introduced shorthand improvements for writing objects in JavaScript. These are called enhanced object literals, and they help you write cleaner code with less repetition.

The three main upgrades 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 theme = "dark";
let layout = "grid";

// Old way
let config1 = { theme: theme, layout: layout };

// ES6 shorthand (same name, write once)
let config2 = { theme, layout };

console.log(config2); // Output: { theme: 'dark', layout: 'grid' }

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 = "panel";

let layout = {
  [prefix + "1"]: "sidebar",
  [prefix + "2"]: "navbar"
};

console.log(layout); // Output: { panel1: 'sidebar', panel2: 'navbar' }

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 config = {
  title: "Dashboard",
  display: {
    columns: 3
  }
};

// Without optional chaining (can throw error)
console.log(config.display.columns);     // Output: 3
console.log(config.toolbar.position);    // TypeError: Cannot read properties of undefined

// With optional chaining (safe)
console.log(config.display?.columns);    // Output: 3
console.log(config.toolbar?.position);   // 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 dashboard = {
  header: {
    title: "Main Panel",
    toolbar: null
  }
};

// Old way (verbose)
if (dashboard && dashboard.header && dashboard.header.toolbar && dashboard.header.toolbar.actions) {
  console.log(dashboard.header.toolbar.actions);
}

// With optional chaining (clean)
if (dashboard?.header?.toolbar?.actions) {
  console.log(dashboard.header.toolbar.actions);
} else {
  console.log("No actions found"); // Output: No actions 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 = {
  widgets: ["chart", "table"]
};

let emptyData = {};

// Safely access first widget
console.log(data.widgets?.[0]);       // Output: chart
console.log(emptyData.widgets?.[0]);  // Output: undefined (no error)

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

let hasWidgets2 = emptyData.widgets?.length > 0;
console.log(hasWidgets2); // 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: { theme } instead of { theme: theme }.
  • 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.

What's next? Now that you can write cleaner object code, let's explore browser-related APIs in the BOM tutorial.

Videos for this topic will be added soon.