10 Hidden JavaScript Gems You Should Know

15 Hidden JavaScript Gems You Should Know

10 Hidden JavaScript Gems You Should Know

Introduction

The foundation of web development, JavaScript, is a flexible language that powers the interactive elements of webpages and online apps. Although most people are familiar with its basics, there are a lot of lesser-known features, methods, and approaches that may greatly improve your knowledge of JavaScript. These are known as hidden gems. We’ll explore 10 such obscure JavaScript nuggets in-depth in this extensive book, including with code samples, to expand your toolkit for programming.

1. JavaScript Nullish Coalescing Operator (??):

Introduced in ECMAScript 2020 (ES11), the Nullish Coalescing Operator (??) is a relatively new innovation to the JavaScript language. It offers a clear and practical method for dealing with variables that could have null or undefined default values.

Syntax:

const result = valueToCheck ?? defaultValue;

Explanation:

  • The expression valueToCheck ?? defaultValue evaluates to valueToCheck if it is neither null nor undefined. Otherwise, it returns defaultValue.
  • The operator differs from the logical OR operator (||) in that it specifically checks for null or undefined values, not just falsy values like empty strings, zero, etc.

Use Cases:

  1. Handling Default Values:
   const username = userInput ?? 'Guest';
  1. Avoiding Errors with Optional Chaining:
   const length = options?.user?.name?.length ?? 0;
  1. Working with Nullable Values:
   const price = product?.price ?? 0;
  1. Setting Default Function Parameters:
   function greet(name) {
     name = name ?? 'Friend';
     console.log(`Hello, ${name}!`);
   }

Example:

const userInput = null;
const username = userInput ?? 'Guest';
console.log(username); // Output: "Guest"

Advantages:

  • Clarity: Enhances code readability by explicitly handling nullish values.
  • Conciseness: Reduces the need for verbose null checks.
  • Robustness: Provides a more reliable alternative to the logical OR operator (||) when dealing with null or undefined values.

Considerations:

  • Browser Support: While modern browsers and Node.js versions support the nullish coalescing operator, ensure compatibility with your target environment.
  • Semantic Differences: Understand the distinction between nullish coalescing (??) and logical OR (||) operators to avoid unexpected behavior.

The Nullish Coalescing Operator is a valuable addition to JavaScript, offering a cleaner and more reliable approach to handling default values in scenarios involving nullable variables. By leveraging this operator, developers can write clearer, more concise code that gracefully handles null and undefined values.

2. JavaScript Optional Chaining (?.):

Optional chaining (?.) is a feature introduced in ECMAScript 2020 (ES11) that simplifies accessing properties of nested objects, especially when some properties along the chain may be null or undefined.

Syntax:

const value = obj?.prop1?.prop2;

Explanation:

  • The optional chaining operator (?.) allows accessing nested properties of an object without the need for explicit null or undefined checks.
  • If any property in the chain is null or undefined, the expression short-circuits, and the result is undefined.
  • It is particularly useful for dealing with data from external sources or APIs where the structure may be unpredictable.

Use Cases:

  1. Accessing Nested Properties:
   const city = user?.address?.city;
  1. Invoking Methods on Optional Objects:
   const result = obj?.method?.();
  1. Combining with Nullish Coalescing Operator:
   const value = obj?.prop ?? defaultValue;
  1. Iterating over Arrays in Objects:
   const firstElement = obj?.array?.[0];

Example:

const user = {
  name: 'John',
  address: null
};

const city = user?.address?.city;
console.log(city); // Output: undefined

Advantages:

  • Null Safety: Prevents errors and exceptions caused by accessing properties of null or undefined objects.
  • Simplicity: Simplifies code by reducing the need for verbose null checks.
  • Readability: Improves code readability by clearly indicating optional properties in the access chain.

Considerations:

  • Browser Support: While most modern browsers and Node.js versions support optional chaining, verify compatibility with your target environment.
  • Learning Curve: Ensure developers are familiar with this feature to leverage its benefits effectively.
  • Combining with Other Features: Understand how optional chaining interacts with other language features, such as the nullish coalescing operator and object destructuring.

Optional chaining offers a streamlined approach to accessing properties of nested objects in JavaScript, enhancing code robustness and readability. By embracing this feature, developers can write cleaner, more concise code that gracefully handles optional properties, resulting in more maintainable and error-resistant applications.

3. JavaScript String.padStart() and String.padEnd():

The String.padStart() and String.padEnd() methods are invaluable tools introduced in ECMAScript 2017 (ES8) for padding strings with another string until they reach a desired length. These methods offer a straightforward and efficient way to format strings, ensuring consistent alignment and presentation.

String.padStart()

Syntax:

string.padStart(targetLength [, padString])

Parameters:

  • targetLength: The desired length of the resulting string after padding.
  • padString (optional): The string to pad the original string with. Defaults to a space if not provided.

Example:

const paddedString = '5'.padStart(4, '0');
console.log(paddedString); // Output: "0005"

String.padEnd()

Syntax:

string.padEnd(targetLength [, padString])

Parameters:

  • targetLength: The desired length of the resulting string after padding.
  • padString (optional): The string to pad the original string with. Defaults to a space if not provided.

Example:

const paddedString = 'Hello'.padEnd(10, '!');
console.log(paddedString); // Output: "Hello!!!!!"

Explanation:

  • Both methods ensure that the resulting string reaches the specified length by appending or prepending the padding string as necessary.
  • If the length of the original string equals or exceeds the target length, no padding occurs, and the original string is returned unchanged.
  • The padStart() method pads the beginning of the string, while the padEnd() method pads the end.

Use Cases:

  1. Formatting Numbers:
   const paddedNumber = '123'.padStart(5, '0');
   console.log(paddedNumber); // Output: "00123"
  1. Aligning Text in Tables:
   const tableHeader = 'Column'.padEnd(10);
   console.log(tableHeader); // Output: "Column    "
  1. Creating Fixed-Length Strings:
   const fixedLengthString = 'Hello'.padEnd(10, '.');
   console.log(fixedLengthString); // Output: "Hello....."
  1. Generating Identifiers:
   const userId = 'user123'.padStart(10, '0');
   console.log(userId); // Output: "000user123"

Advantages:

  • Simplicity: Provides a straightforward method for padding strings without custom loops or calculations.
  • Consistency: Ensures consistent formatting and alignment of strings, improving readability and presentation.
  • Flexibility: Allows specifying the padding character or string, accommodating various formatting requirements.

Considerations:

  • Performance: While generally efficient, excessive use of padding operations on large strings may impact performance.
  • Padding Characters: Choose padding characters carefully to ensure they align with the desired formatting style.
  • Cross-Browser Compatibility: Confirm compatibility with older browsers or environments where ES8 features may not be fully supported.

4. JavaScript Object.fromEntries():

ECMAScript 2019 (ES10) introduces the Object.fromEntries() function, which offers an easy way to convert an array of key-value pairs into an object. By enabling the reverse translation, this function enhances Object.entries(), which provides an array of key-value pairs from an object.

Syntax:

Object.fromEntries(iterable)

Parameters:

  • iterable: An iterable object (such as an array or a map) containing key-value pairs.

Example:

const entries = [['a', 1], ['b', 2]];
const obj = Object.fromEntries(entries);
console.log(obj); // Output: { a: 1, b: 2 }

Explanation:

  • Object.fromEntries() takes an iterable containing key-value pairs and returns a new object where each pair becomes a property-value pair in the resulting object.
  • Each entry in the iterable should be an array where the first element represents the property key and the second element represents the corresponding value.
  • This method simplifies the creation of objects from arrays, particularly when dealing with data in key-value pair format, such as the result of Object.entries() or data obtained from APIs.

Use Cases:

  1. Converting Arrays to Objects:
   const entries = [['a', 1], ['b', 2]];
   const obj = Object.fromEntries(entries);
  1. Manipulating Data Structures:
   const map = new Map([['x', 10], ['y', 20]]);
   const obj = Object.fromEntries(map);
  1. Parsing Data:
   const queryString = 'key1=value1&key2=value2';
   const params = Object.fromEntries(new URLSearchParams(queryString).entries());

Advantages:

  • Conciseness: Provides a concise and readable syntax for transforming arrays of key-value pairs into objects.
  • Ease of Use: Simplifies working with data structures like arrays and maps, enhancing code clarity and maintainability.
  • Compatibility: Complements Object.entries(), enabling bidirectional conversion between objects and arrays of key-value pairs.

Considerations:

  • Browser Support: Ensure compatibility with target environments, as Object.fromEntries() may not be supported in older browsers or Node.js versions.
  • Data Integrity: Verify that the input iterable contains valid key-value pairs, as unexpected entries may lead to errors or unexpected behavior.
  • Performance: While generally efficient, excessive use of Object.fromEntries() on large datasets may impact performance.

5. JavaScript Array.flatMap():

The Array.flatMap() method is a powerful addition to JavaScript arrays introduced in ECMAScript 2019 (ES10). It combines the functionalities of both map() and flat() methods, allowing you to map each element of an array to a new array and then flatten the result into a single array.

Syntax:

array.flatMap(callback(currentValue, index, array), thisArg)

Parameters:

  • callback: A function that produces an array of values. It accepts three arguments:
  • currentValue: The current element being processed in the array.
  • index (optional): The index of the current element being processed in the array.
  • array (optional): The array flatMap() was called upon.
  • thisArg (optional): Value to use as this when executing the callback.

Example:

const numbers = [1, 2, 3];
const doubled = numbers.flatMap(num => [num, num * 2]);
console.log(doubled); // Output: [1, 2, 2, 4, 3, 6]

Explanation:

  • The flatMap() method iterates over each element of the array and calls the callback function for each element.
  • The callback function should return an array for each element. The elements of these arrays are then flattened into the resulting array.
  • If the callback function returns a non-array value, it will be flattened into the resulting array as a single element.

Use Cases:

  1. Flattening Arrays:
   const arrays = [[1, 2], [3, 4], [5, 6]];
   const flattened = arrays.flatMap(array => array);
   console.log(flattened); // Output: [1, 2, 3, 4, 5, 6]
  1. Mapping and Flattening:
   const words = ['Hello', 'World'];
   const letters = words.flatMap(word => word.split(''));
   console.log(letters); // Output: ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']
  1. Removing Empty Slots:
   const arr = [1, , 2, , 3];
   const filtered = arr.flatMap(item => item ? [item] : []);
   console.log(filtered); // Output: [1, 2, 3]

Advantages:

  • Simplicity: Combines mapping and flattening operations into a single method call, reducing code complexity.
  • Efficiency: Provides a more concise and performant alternative to manually chaining map() and flat() methods.
  • Versatility: Offers flexibility for various data manipulation tasks, including transforming and flattening arrays.

Considerations:

  • Browser Support: Ensure compatibility with target environments, as flatMap() may not be supported in older browsers or Node.js versions.
  • Nested Arrays: Be mindful of potential nested arrays returned by the callback function, as they may lead to unexpected results if not flattened correctly.
  • Callback Function: Ensure the callback function returns arrays consistently to avoid unexpected behavior.

6. JavaScript BigInt:

BigInt is a relatively recent addition to JavaScript, introduced in ECMAScript 2020 (ES11). It is a numeric primitive that enables the representation of integers with arbitrary precision, overcoming the limitations of the Number type, which can only represent numbers accurately up to a certain size.

Syntax:

const bigNum = 1234567890123456789012345678901234567890n;

Explanation:

  • BigInt literals are created by appending an ‘n’ to the end of an integer or by calling the BigInt constructor.
  • BigInt values can represent integers with arbitrary precision, limited only by available memory.
  • BigInt values can be used in mathematical operations and compared with other BigInts or Numbers.

Use Cases:

  1. Handling Large Integers:
   const bigNum = 1234567890123456789012345678901234567890n;
  1. Working with Financial Data:
   const balance = 10000000000000000000n; // Represents $10,000
  1. Cryptography:
    BigInts are commonly used in cryptographic algorithms where precision and accuracy are crucial.

Advantages:

  • Arbitrary Precision: BigInts can represent integers of any size, limited only by available memory.
  • Accurate Arithmetic: BigInt arithmetic is precise, ensuring accurate calculations for large integers.
  • Compatibility: BigInts can be used alongside standard Number values in JavaScript, enabling seamless integration with existing code.

Considerations:

  • Type Coercion: BigInts and Numbers are distinct types and cannot be directly mixed in arithmetic operations without explicit conversion.
  • Performance: BigInt operations may be slower than standard Number operations due to the additional complexity of arbitrary precision arithmetic.
  • Browser Support: Ensure compatibility with target environments, as BigInts may not be supported in older browsers or Node.js versions.

7. JavaScript Promise.allSettled():

Assured.A JavaScript function called allSettled() was first included in ECMAScript 2020 (ES11). It permits you to manage several promises at once and obtain a single promise that resolves upon the fulfillment or rejection of every promise, irrespective of their respective results. When you need to run several asynchronous actions and handle each result separately, this is quite helpful.

Syntax:

Promise.allSettled(iterable);

Parameters:

  • iterable: An iterable (such as an array) containing promises.

Example:

const promises = [
  Promise.resolve('Resolved'),
  Promise.reject('Rejected'),
  Promise.resolve('Resolved again')
];

Promise.allSettled(promises)
  .then(results => {
    results.forEach(result => {
      if (result.status === 'fulfilled') {
        console.log('Fulfilled:', result.value);
      } else {
        console.log('Rejected:', result.reason);
      }
    });
  });

Explanation:

  • Promise.allSettled() takes an iterable of promises as input and returns a single promise.
  • The returned promise resolves after all the promises in the iterable have settled (fulfilled or rejected).
  • The result of Promise.allSettled() is an array of objects representing the outcome of each promise. Each object has two properties: status and value (or reason if the promise was rejected).
  • This method differs from Promise.all(), which rejects immediately if any promise in the iterable rejects. Promise.allSettled() waits for all promises to settle, regardless of their individual outcomes.

Use Cases:

  1. Batch Requests: When making multiple HTTP requests concurrently and needing to process all responses, regardless of success or failure.
  2. Data Fetching: When fetching data from multiple sources and needing to handle each response independently.
  3. Error Handling: When needing to catch and handle errors for each promise individually, without aborting the entire operation.

Advantages:

  • Error Tolerance: Guarantees that all promises will settle, allowing you to handle each result individually, even if some promises reject.
  • Concise Error Handling: Simplifies error handling logic by providing a uniform interface for handling both fulfilled and rejected promises.
  • Independent Processing: Enables independent processing of each promise’s result, facilitating parallel execution of asynchronous operations.

Considerations:

  • Browser Support: Verify compatibility with target environments, as Promise.allSettled() may not be supported in older browsers or Node.js versions.
  • Polyfill: Consider using a polyfill if support for older environments is required.
  • Promise Order: Note that the order of results in the output array corresponds to the order of promises in the input iterable, not the order of settlement.

8. JavaScript Intl.DateTimeFormat:

A built-in JavaScript object called Intl.DateTimeFormat was first made available in the ECMAScript Internationalization API (ECMA-402) and offers a method of formatting dates and times based on the user’s environment’s locale. With this object, developers may construct date and time formatting that is particular to a certain locale, making it possible for apps to display dates and times in a way that is both user-friendly and culturally suitable.

Syntax:

new Intl.DateTimeFormat([locales[, options]])

Parameters:

  • locales (optional): A string or an array of strings specifying the locale or locales to use for formatting. If not provided, the default locale of the runtime environment is used.
  • options (optional): An object containing various properties for customizing the formatting behavior, such as localeMatcher, dateStyle, timeStyle, timeZone, etc.

Example:

const date = new Date();
const formattedDate = new Intl.DateTimeFormat('en-US').format(date);
console.log(formattedDate); // Output: "4/1/2024" (for April 1, 2024)

Explanation:

  • The Intl.DateTimeFormat object is instantiated with the desired locale (e.g., 'en-US' for English (United States)).
  • The format() method of the Intl.DateTimeFormat object is then called with a Date object as an argument to format the date according to the specified locale.
  • The result is a string representing the formatted date and/or time according to the locale-specific conventions.

Use Cases:

  1. Localized Date Display: Presenting dates in a format familiar to users based on their locale preferences.
  2. Timezone Conversion: Formatting dates and times in specific timezones for international applications.
  3. Customized Formatting: Tailoring the date and time format based on user preferences or application requirements.
  4. Internationalization: Supporting multiple languages and regions by adapting date and time formats accordingly.

Advantages:

  • Locale-Specific Formatting: Provides locale-aware date and time formatting, ensuring consistency and cultural appropriateness.
  • Customization: Offers a range of options for customizing the formatting, such as date style, time style, timezone, and more.
  • Internationalization Support: Facilitates the internationalization of applications by adapting to the language and cultural conventions of different locales.

Considerations:

  • Browser Support: Verify compatibility with target environments, as Intl.DateTimeFormat may not be supported in older browsers or Node.js versions.
  • Locale Data: Ensure that locale data is available in the runtime environment to correctly format dates and times for different locales.
  • Options: Familiarize yourself with available formatting options to tailor the output according to specific requirements.

9. JavaScript Web Storage API:

A user’s browser may store key-value pairs locally thanks to the Web Storage API. It is composed of two mechanisms: sessionStorage and localStorage, each of which provides a distinct lifespan and scope for the data that is saved. These storage methods provide an easy way to transfer data across many pages within the same origin or persist data between sessions.

localStorage:

  • localStorage stores data with no expiration date. This means the data will persist even after the browser window is closed and reopened.
  • The data stored in localStorage remains available until explicitly cleared by the user or the web application.
  • Data stored in localStorage is scoped to the origin, meaning it is accessible only from pages served from the same domain and protocol.

sessionStorage:

  • sessionStorage stores data for the duration of the page session. This means the data is cleared when the page session ends, typically when the browser tab is closed.
  • Each page or tab has its own separate sessionStorage, ensuring that data is not shared between different pages or tabs.
  • Similar to localStorage, data stored in sessionStorage is scoped to the origin.

Usage:

  1. Storing Data:
   // Storing data in localStorage
   localStorage.setItem('key', 'value');

   // Storing data in sessionStorage
   sessionStorage.setItem('key', 'value');
  1. Retrieving Data:
   // Retrieving data from localStorage
   const value = localStorage.getItem('key');

   // Retrieving data from sessionStorage
   const value = sessionStorage.getItem('key');
  1. Removing Data:
   // Removing data from localStorage
   localStorage.removeItem('key');

   // Removing data from sessionStorage
   sessionStorage.removeItem('key');

Use Cases:

  1. User Preferences: Storing user preferences or settings to provide a personalized experience.
  2. Caching Data: Storing frequently accessed data to reduce server requests and improve performance.
  3. Authentication Tokens: Storing authentication tokens or session identifiers for user authentication.
  4. Offline Applications: Storing data locally to enable offline functionality in web applications.

Advantages:

  • Persistence: Provides a way to persist data locally within the browser, allowing applications to remember user preferences and settings.
  • Convenience: Offers a simple and easy-to-use API for storing and retrieving data without the need for server-side storage.
  • Performance: Accessing data from local storage is faster than fetching data from a remote server, improving application responsiveness.

Considerations:

  • Storage Limits: Both localStorage and sessionStorage have storage limits (usually around 5-10 MB per origin), so it’s important to be mindful of the amount of data stored.
  • Security: Avoid storing sensitive or critical data in local storage, as it is accessible to JavaScript running on the same origin and may be vulnerable to cross-site scripting (XSS) attacks.
  • Data Format: Data stored in web storage is limited to string values. Complex data structures such as objects or arrays need to be serialized and deserialized using methods like JSON.stringify() and JSON.parse().

10. JavaScript Object.freeze():

JavaScript’s Object.freeze() function lets you freeze an object and render it immutable. An object’s properties cannot be added, removed, or changed after it has been frozen. By creating objects that are read-only, this technique helps to avoid inadvertently changing their attributes.

Syntax:

Object.freeze(obj)

Parameters:

  • obj: The object to freeze.

Example:

const obj = {
  prop: 'value'
};
Object.freeze(obj);
obj.prop = 'new value'; // This change will not take effect

Explanation:

  • Object.freeze() is called with the object you want to freeze as its argument.
  • Once frozen, attempting to modify the properties of the object, including adding, deleting, or modifying existing properties, will have no effect.
  • If the object contains nested objects, those nested objects are also frozen recursively.

Use Cases:

  1. Immutable Objects: Creating objects whose properties should not change after initialization.
  2. Constants: Defining constants that should not be modified during runtime.
  3. Preventing Mutation: Protecting sensitive data or configurations from accidental modification.
  4. Performance Optimization: Improving performance by ensuring that objects remain constant and can be cached safely.

Advantages:

  • Data Integrity: Ensures that the properties of the object remain unchanged, maintaining data integrity and consistency.
  • Predictability: Prevents unexpected modifications to object properties, reducing bugs and unintended side effects.
  • Security: Protects sensitive data or configurations from unauthorized modifications.
  • Performance: Can improve performance by allowing JavaScript engines to optimize object access and manipulation.

Considerations:

  • Shallow Freeze: Object.freeze() only freezes the top-level properties of an object. If the object contains nested objects, those nested objects are not automatically frozen and must be frozen separately.
  • Strict Mode: In strict mode, attempting to modify a frozen object will throw an error instead of failing silently.
  • Non-extensible Objects: If an object is non-extensible (created with Object.preventExtensions()), it cannot be frozen because freezing implies non-extensibility.

Share this post

Leave a Reply

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