JavaScript: Unique and Lesser-Known Features

These not-so-common javascript features can significantly enhance code quality, readability, and maintainability.

While most developers are familiar with the basics and some of the more popular advanced features of JavaScript, there are several underappreciated gems in the language that often go unnoticed. These features can significantly enhance code quality, readability, and maintainability.


Optional Chaining (`?.`) in Javascript

Optional chaining allows you to read the value of a property within a chain of connected objects without having to check if each reference in the chain is null or undefined.

Without Optional Chaining

let user = { profile: { name: 'John' } };
let name = user && user.profile && user.profile.name;

With Optional Chaining

Reduces the need for verbose and repetitive null checks, leading to cleaner and more readable code. It simplifies the process of dealing with nested structures that may or may not be present.

let name = user?.profile?.name;

Nullish Coalescing Operator (`??`) in Javascript

This operator returns the right-hand operand when the left operand is null or undefined and otherwise returns the left operand.

Benefit: Provides a clearer and more intuitive way to deal with default values. It distinguishes between `null/undefined` and “falsy” values like 0 or ”, preventing unintended behaviour.

let score = 0;
let displayScore = score ?? "Not set";
console.log(displayScore); // Outputs: 0 (because 0 is not null or undefined)

Tagged Template Literals in Javascript

Tagged template literals allow you to parse template literals using a function.

Benefit: Enhances the flexibility of template literals. They can be used for custom string manipulation, localization, styled-components in libraries like Styled Components, and more.

function tag(strings, ...values) {
    console.log(strings);
    console.log(values);
}
 
let age = 30;
tag`User's age is ${age}.`;
// Outputs:
// ["User's age is ", "."]
// [30]

Logical Assignment Operators in Javascript

These operators combine logical operations with assignments.

  • &&= : If the left operand is truthy, assign the value of the right operand to it.`&&=: If the left operand is truthy, assign the value of the right operand to it.
  • ||= : If the left operand is falsy, assign the value of the right operand to it.
  • ??= : If the left operand is null or undefined, assign the value of the right operand to it.

Benefit: Shortens code for common logical operations combined with assignment, making the codebase more concise and potentially improving performance in some cases.

let a = 0;
a ||= 5;
console.log(a); // Outputs: 5
 
let b = "Hello";
b &&= "World";
console.log(b); // Outputs: World
 
let c;
c ??= "Default Value";
console.log(c); // Outputs: Default Value

Dynamic Import in Javascript

It allows you to load modules on demand by using the import() syntax.

Benefit: Improves the performance of web applications by loading code on demand, reducing initial load time. This is particularly beneficial for large applications with multiple features that aren’t all immediately required.

button.addEventListener('click', async () => {
    const module = await import('./someModule.js');
    module.someFunction();
});

BigInt in Javascript

BigInt provides a way to represent whole numbers larger than 2^53 – 1.

Benefit: Allows for precise representation of integers beyond the safe integer limit of JavaScript, which is essential for financial calculations, working with large datasets, cryptography, and more.

const largeNumber = BigInt("9007199254740993");
const anotherLargeNumber = BigInt("2");
console.log(largeNumber + anotherLargeNumber); // 9007199254740995n

Private Class Fields and Methods in Javascript

With the introduction of the class fields proposal, we can now define truly private class fields and methods using a # prefix.

Benefit: Enhances encapsulation in classes, leading to safer and more maintainable code. It ensures internal class details are not accessible from the outside, reducing the risk of unintended interference.

class Counter {
  #count = 0;
 
  increment() {
    this.#count++;
  }
 
  get value() {
    return this.#count;
  }
 
  #logCount() {
    console.log(this.#count);
  }
}
 
const counter = new Counter();
counter.increment();
console.log(counter.value); // 1
// counter.#count; // SyntaxError: Private field '#count' must be declared in an enclosing class
// counter.#logCount(); // SyntaxError

The `in` Operator in Javascript

The in-operator checks if an object has a specific property.

Benefit: Provides a quick and easy way to check for the existence of a property in an object, even if the property is set to undefined or another falsy value.

const person = { name: "Alice", age: 30 };
console.log("name" in person); // true
console.log("height" in person); // false

Promise.allSettled() in Javascript

Waits for all promises to be settled (either resolved or rejected)

Benefit: Allows for handling of multiple promises, ensuring that all promises are settled before proceeding. This is crucial for scenarios where you need to wait for multiple asynchronous operations to complete, regardless of whether they succeed or fail.

const p1 = Promise.resolve(1);
const p2 = Promise.reject('error');
const p3 = Promise.resolve(3);
 
Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach(result => {
    console.log(result.status); // "fulfilled" or "rejected"
    if (result.status === "fulfilled") {
      console.log(result.value);
    } else {
      console.log(result.reason);
    }
  });
});

Numeric Separators in Javascript

Improves the readability of large numbers by using underscores as separators.

Benefit: Enhances the readability of numeric literals, making it easier to read and maintain code, especially when dealing with large numbers.

const billion = 1_000_000_000; // Same as const billion = 1000000000;
const bytes = 0x89_AB_CD_EF;   // Hexadecimal with byte values
const mask = 0b1100_1010;     // Binary representation

String.prototype.matchAll() in Javascript

Returns all matches of a regular expression in a string.

Benefit: Provides a way to perform global matches of a regular expression on a string and iterate through the results, including capturing groups. It’s more powerful and flexible than String.prototype.match() for global searches.

const regex = /t(e)(st(\d?))/g;
const str = 'test1test2';
for (const match of str.matchAll(regex)) {
  console.log(match);
}

Object.fromEntries()

It transforms a list of key-value pairs into an object.

Benefit: Offers a straightforward way to transform key-value pairs into an object. This is particularly useful when working with Map objects or other iterable key-value pairs.

const entries = [['name', 'John'], ['age', 30]];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: "John", age: 30 }

Array.flat() and Array.flatMap()

Array.flat() is used to flatten nested arrays.

Benefit: Simplifies the process of flattening arrays, reducing the need for recursion or complex loops. Array.flatMap() in particular combines mapping and flattening, which can be more efficient than using map() followed by flat().

const arr = [1, [2, [3, [4]], 5]];
console.log(arr.flat(2)); // [1, 2, 3, [4], 5]
 
# Array.flatMap() is a combination of map and flat
 
const arr = [1, 2, 3, 4];
const result = arr.flatMap(x => [x, x * 2]);
console.log(result); // [1, 2, 2, 4, 3, 6, 4, 8]

Conclusion

Understanding these features will allow developers to write more efficient and readable JavaScript code. Incorporating them into regular development can be a game-changer!

On my Twitter and Instagram accounts, I frequently share my programming journey and development experiences.