Tari Ibaba

Tari Ibaba is a software developer with years of experience building websites and apps. He has written extensively on a wide range of programming topics and has created dozens of apps and open-source libraries.

How to Get a Month Number from Month Name in JavaScript

In this article, we’ll learn how to use JavaScript to get the position of a month in the list of the 12 months from its name. That is, we’ll get 1 from January, 2 from February, 3 from March, and so on.

To do this, create a date string from the name and pass this string to the Date() constructor. Then use the getMonth() method to get the month number. For example:

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('January')); // 1
console.log(getMonthNumberFromName('February')); // 2
console.log(getMonthNumberFromName('March')); // 3

We interpolate the month into a string that can be parsed by the Date() constructor to create a new Date object. Then we use the getMonth() method to get the month of the date.

The getMonth() method returns a zero-based index of the month, i.e., 0 for January, 1 for February, 2 for March, etc.

const month1 = new Date('January 1, 2022').getMonth();
console.log(month1); // 0

const month2 = new Date('February 1, 2022').getMonth();
console.log(month2); // 1

This is why we add 1 to it and return the sum from as the result.

Our function will also work for abbreviated month names, as the Date() constructor can also parse date strings with them.

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('Jan')); // 1
console.log(getMonthNumberFromName('Feb')); // 2
console.log(getMonthNumberFromName('Mar')); // 3

If the month name is such that the resulting date string can’t be parsed by the Date() constructor, an invalid date will be created and getMonth() will return NaN.

const date = new Date('Invalid 1, 2022');

console.log(date); // Invalid Date
console.log(date.getMonth()); // NaN

This means our function will return NaN as well:

function getMonthNumberFromName(monthName) {
  return new Date(`${monthName} 1, 2022`).getMonth() + 1;
}

console.log(getMonthNumberFromName('Invalid')); // NaN

It might be better if we return -1 instead. We can check for an invalid date with the isNaN() function.

function getMonthNumberFromName(monthName) {
  const date = new Date(`${monthName} 1, 2022`);

  if (isNaN(date)) return -1;

  return date.getMonth() + 1;
}

console.log(getMonthNumberFromName('Invalid')); // -1

Alternatively, we could throw an error:

function getMonthNumberFromName(monthName) {
  const date = new Date(`${monthName} 1, 2022`);

  if (isNaN(date)) {
    throw new Error('Invalid month name.');
  }

  return date.getMonth() + 1;
}

// Error: Invalid month name.
console.log(getMonthNumberFromName('Invalid'));

How to Add 1 Year to a Date in JavaScript

Let’s look at some ways to easily add 1 year to a Date object in JavaScript.

1. Date setFullYear() and getFullYear() Methods

To add 1 year to a date, call the getFullYear() method on the date to get the year, then call the setFullYear() method on the date, passing the sum of getFullYear() and 1 as an argument, i.e., date.setFullYear(date.getFullYear() + 1).

For example:

function addOneYear(date) {
  date.setFullYear(date.getFullYear() + 1);
  return date;
}

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addOneYear(date);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

Our addOneYear() function takes a Date object and returns the same Date with the year increased by 1.

The Date getFullYear() method returns a number that represents the year of a particular date.

The Date setFullYear() method sets the year of a date to a specified number.

Avoiding Side Effects

The setFullYear() method mutates the Date object it is called on. This introduces a side effect into our addOneYear() function. To avoid modifying the passed Date and create a pure function, make a copy of the Date and call setFullYear() on this copy, instead of the original.

function addOneYear(date) {
  // Making a copy with the Date() constructor
  const dateCopy = new Date(date);

  dateCopy.setFullYear(dateCopy.getFullYear() + 1);

  return dateCopy;
}

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addOneYear(date);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-04-20T00:00:00.000Z

Functions that don’t modify external state (i.e., pure functions) tend to be more predictable and easier to reason about. This makes it a good practice to limit the number of side effects in your programs.

2. date-fns addYears() Function

Alternatively, we can use the pure addYears() function from the date-fns NPM package to quickly add 1 year to a date.

import { addYears } from 'date-fns';

// April 20, 2022
const date = new Date('2022-04-20T00:00:00.000Z');

const newDate = addYears(date, 1);

// April 20, 2023
console.log(newDate); // 2023-04-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-04-20T00:00:00.000Z

This function takes a Date object and the number of years to add as arguments, and returns a new Date object with the newly added years. It does not modify the original date passed to it.

How to Check if a String is a URL in JavaScript

In this article, we’ll be looking at multiple ways to easily check if a string is a valid URL in JavaScript.

1. Catch Exception from URL() Constructor

To check if a string is a URL, pass the string to the URL() constructor. If the string is a valid URL, a new URL object will be created successfully. Otherwise, an error will be thrown. Using a try...catch block, we can handle the error and perform the appropriate action when the URL is invalid.

For example:

function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch (err) {
    return false;
  }
}

console.log(isValidUrl('https://codingbeautydev.com')); // true
console.log(isValidUrl('app://codingbeautydev.com')); // true
console.log(isValidUrl('Coding Beauty')); // false

To check for a valid HTTP URL, we can use the protocol property of the URL object.

function isValidHttpUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch (err) {
    return false;
  }
}

console.log(isValidHttpUrl('https://codingbeautydev.com')); // true
console.log(isValidHttpUrl('app://codingbeautydev.com')); // false
console.log(isValidHttpUrl('Coding Beauty')); // false

The URL protocol property returns a string representing the protocol scheme of the URL, including the final colon (:). HTTP URLs have a protocol of either http: or https:.

2. Regex Matching

Alternatively, we can check if a string is a URL using a regular expression. We do this by calling the test() method on a RegExp object with a pattern that matches a string that is a valid URL.

function isValidUrl(str) {
  const pattern = new RegExp(
    '^([a-zA-Z]+:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
    'i'
  );
  return pattern.test(str);
}

console.log(isValidUrl('https://codingbeautydev.com')); // true
console.log(isValidUrl('app://codingbeautydev.com')); // true
console.log(isValidUrl('Coding Beauty')); // false

The RegExp test() method searches for a match between a regular expression and a string. It returns true if it finds a match. Otherwise, it returns false.

To check for a valid HTTP URL, we can alter the part of the regex that matches the URL protocol:

function isValidHttpUrl(str) {
  const pattern = new RegExp(
    '^(https?:\\/\\/)?' + // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
      '(\\#[-a-z\\d_]*)?$', // fragment locator
    'i'
  );
  return pattern.test(str);
}

console.log(isValidHttpUrl('https://codingbeautydev.com')); // true
console.log(isValidHttpUrl('app://codingbeautydev.com')); // false
console.log(isValidHttpUrl('Coding Beauty')); // false

The https?: pattern will only match either http: or https:.

3. is-url and is-url-http NPM Packages

We can also use the is-url NPM package to quickly check if a string is a valid URL.

import isUrl from 'is-url';

console.log(isUrl('https://codingbeautydev.com')); // true
console.log(isUrl('app://codingbeautydev.com')); // true
console.log(isUrl('Coding Beauty')); // false

To quickly check if a string is a valid HTTP URL, we can use the is-url-http package from NPM.

import isUrlHttp from 'is-url-http';

console.log(isUrlHttp('https://codingbeautydev.com')); // true
console.log(isUrlHttp('app://codingbeautydev.com')); // false
console.log(isUrlHttp('Coding Beauty')); // false

How to Convert Hex to Decimal in JavaScript

In this article, we’re going to learn how to convert a hexadecimal number to its decimal equivalent in JavaScript. And we’ll look at some real-world scenarios where we’ll need to do this.

parseInt() function

To convert a hex to decimal, call the parseInt() function, passing the hex and 16 as the first and second arguments respectively, i.e., parseInt(hex, 16). For example:

function hexToDec(hex) {
  return parseInt(hex, 16);
}

console.log(hexToDec('f')); // 15
console.log(hexToDec('abc')); // 2748
console.log(hexToDec(345)); // 837

The parseInt() function parses a string and returns an integer of the specified radix. It has two parameters:

  1. string – the string to be parsed.
  2. radix – an integer between 2 and 36 that represents the radix/base of the string.

parseInt() ignores any leading whitespace in the string passed to it.

console.log(parseInt('   a', 16)); // 10
console.log(parseInt('   cd', 16)); // 205

If the string passed is not a valid number in the specified radix, parseInt() does not throw an error, but returns NaN.

console.log(parseInt('js', 16)); // NaN

// 'a' does not exist in base 10
console.log(parseInt('a', 10)); // NaN

// 5 does not exist in base 2
console.log(parseInt(5, 2)); // NaN

If the radix is not between 2 and 36, parseInt() will return NaN also.

console.log(parseInt(54, 1));
console.log(parseInt('aa', 37));
console.log(parseInt(10, 50));

If the radix is an invalid number or not set and the string starts with 0x or 0X, then the radix is assumed to be 16. But if the string starts with any other value, the radix is assumed to be 10.

// base 10 assumed
console.log(parseInt('45')); // 45
console.log(parseInt('36', 'invalid')); // 36

// 'f' and 'b' do NOT exist in assumed base 10
console.log(parseInt('ff')); // NaN
console.log(parseInt('bb', 'invalid')); // NaN

// 'f' and 'b' do exist in assumed base 16
console.log(parseInt('0xff')); // 255
console.log(parseInt('0Xbb', 'invalid')); // 187

Use case: convert hex codes to RGB(A)

One common use of converting hex values to decimal is to convert a color hex code to its RGB format equivalent. Here’s how we can do it:

function hexToDec(hex) {
  return parseInt(hex, 16);
}

function hexToRGB(hexColor) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor);
  return {
    r: hexToDec(result[1]),
    g: hexToDec(result[2]),
    b: hexToDec(result[3]),
  };
}

// { r: 255, g: 128, b: 237 }
console.log(hexToRGB('#ff80ed'));

// { r: 195, g: 151, b: 151 }
console.log(hexToRGB('#c39797'));

// { r: 255, g: 255, b: 255 }
console.log(hexToRGB('#ffffff'));

We created a reusable hexToRGB() function to convert the hex color codes to their equivalent RGB format.

We use a regex to match and separate the two-letter codes representing red (R), green (G), and blue (B). We call the exec() method to find the matches of this regex in the specified hex color code.

/**
[
  '#ff80ed',
  'ff',
  '80',
  'ed',
  index: 0,
  input: '#ff80ed',
  groups: undefined
]
 */
console.log(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec('#ff80ed'));

After separating them, we use our hexToDec() method to convert each of them to its decimal equivalent.

We return an object with r, g and b properties containing the values for red, green, and blue respectively.

Depending on our use case, we could return an rgb() string instead of an object. This could be useful for color animation, as some animation libraries work with RGB values but not with hex color codes.

function hexToDec(hex) {
  return parseInt(hex, 16);
}

function hexToRGB(hexColor) {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor);
  const r = hexToDec(result[1]);
  const g = hexToDec(result[2]);
  const b = hexToDec(result[3]);

  return `rgb(${r}, ${g}, ${b})`;
}

// rgb(255, 128, 237)
console.log(hexToRGB('#ff80ed'));

// rgb(195, 151, 151)
console.log(hexToRGB('#c39797'));

// rgb(255, 255, 255)
console.log(hexToRGB('#ffffff'));

We could modify the function to detect alpha values in the hex code and convert the color code to an RGBA format instead. We’ll use an alpha of 1 if it is not specified.

function hexToDec(hex) {
  return parseInt(hex, 16);
}

function hexToRGBA(hexColor) {
  const regex = /^#?([a-f\d]{2})?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  const result = regex.exec(hexColor);

  const alphaHex = result[1];
  const a = alphaHex ? hexToDec(alphaHex) / 255 : 1;
  const r = hexToDec(result[2]);
  const g = hexToDec(result[3]);
  const b = hexToDec(result[4]);

  return { r, g, b, a };
}

// { r: 255, g: 128, b: 237, a: 1 }
console.log(hexToRGBA('#ff80ed'));

// { r: 195, g: 151, b: 151, a: 1 }
console.log(hexToRGBA('#c39797'));

// { r: 255, g: 128, b: 237, a: 0.8666666666666667 }
console.log(hexToRGBA('#ddff80ed'));

// { r: 195, g: 151, b: 151, a: 0.6901960784313725 }
console.log(hexToRGBA('#b0c39797'));

And we could also return an rgba() string instead of an object:

function hexToDec(hex) {
  return parseInt(hex, 16);
}

function hexToRGBA(hexColor) {
  const regex = /^#?([a-f\d]{2})?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  const result = regex.exec(hexColor);

  const alphaHex = result[1];
  const a = alphaHex ? hexToDec(alphaHex) / 255 : 1;
  const r = hexToDec(result[2]);
  const g = hexToDec(result[3]);
  const b = hexToDec(result[4]);

  return `rgba(${r}, ${g}, ${b}, ${a.toFixed(3)})`;
}

// rgba(255, 128, 237, 1.000)
console.log(hexToRGBA('#ff80ed'));

// rgba(195, 151, 151, 1.000)
console.log(hexToRGBA('#c39797'));

// rgba(255, 128, 237, 0.867)
console.log(hexToRGBA('#ddff80ed'));

// rgba(195, 151, 151, 0.690)
console.log(hexToRGBA('#b0c39797'));

11 Amazing New JavaScript Features in ES13 (ES2022)

Like a lot of other programming languages, JavaScript is constantly evolving. Every year, the language is made more powerful with new capabilities that let developers write more expressive and concise code.

Let’s explore the most recent features added in ECMAScript 2022 (ES13), and see examples of their usage to understand them better.

1. Class Field Declarations

Before ES13, class fields could only be declared in the constructor. Unlike in many other languages, we could not declare or define them in the outermost scope of the class.

class Car {
  constructor() {
    this.color = 'blue';
    this.age = 2;
  }
}

const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2

ES2022 removes this limitation. Now we can write code like this:

class Car {
  color = 'blue';
  age = 2;
}

const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2

2. Private Methods and Fields

Previously, it was not possible to declare private members in a class. A member was traditionally prefixed with an underscore (_) to indicate that it was meant to be private, but it could still be accessed and modified from outside the class.

class Person {
  _firstName = 'Joseph';
  _lastName = 'Stevens';

  get name() {
    return `${this._firstName} ${this._lastName}`;
  }
}

const person = new Person();
console.log(person.name); // Joseph Stevens

// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens

// They can also be modified
person._firstName = 'Robert';
person._lastName = 'Becker';

console.log(person.name); // Robert Becker

With ES13, we can now add private fields and members to a class, by prefixing it with a hashtag (#). Trying to access them from outside the class will cause an error:

class Person {
  #firstName = 'Joseph';
  #lastName = 'Stevens';

  get name() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

const person = new Person();
console.log(person.name);

// SyntaxError: Private field '#firstName' must be
// declared in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);

Note that the error thrown here is a syntax error, which happens at compile time, so no part of the code runs. The compiler doesn’t expect you to even try to access private fields from outside a class, so it assumes you’re trying to declare one.

3. await Operator at the Top Level

In JavaScript, the await operator is used to pause execution until a Promise is settled (fulfilled or rejected).

Previously, we could only use this operator in an async function – a function declared with the async keyword. We could not do so in the global scope.

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, timeout);
  });
}

// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);

With ES2022, now we can:

function setTimeoutAsync(timeout) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, timeout);
  });
}

// Waits for timeout - no error thrown
await setTimeoutAsync(3000);

4. Static Class Fields and Static Private Methods

We can now declare static fields and static private methods for a class in ES13. Static methods can access other private/public static members in the class using the this keyword, and instance methods can access them using this.constructor.

class Person {
  static #count = 0;

  static getCount() {
    return this.#count;
  }

  constructor() {
    this.constructor.#incrementCount();
  }

  static #incrementCount() {
    this.#count++;
  }
}

const person1 = new Person();
const person2 = new Person();

console.log(Person.getCount()); // 2

5. Class static Block

ES13 allows the definition of static blocks that will be executed only once, at the creation of the class. This is similar to static constructors in other languages with support for object-oriented programming, like C# and Java.

A class can have any number of static {} initialization blocks in its class body. They will be executed, along with any interleaved static field initializers, in the order they are declared. We can use the super property in a static block to access properties of the super class.

class Vehicle {
  static defaultColor = 'blue';
}

class Car extends Vehicle {
  static colors = [];

  static {
    this.colors.push(super.defaultColor, 'red');
  }

  static {
    this.colors.push('green');
  }
}

console.log(Car.colors); // [ 'blue', 'red', 'green' ]

6. Ergonomic Brand Checks for Private Fields

We can use this new ES2022 feature to check if an object has a particular private field in it, using the in operator.

class Car {
  #color;

  hasColor() {
    return #color in this;
  }
}

const car = new Car();
console.log(car.hasColor()); // true;

The in operator is able to correctly distinguish private fields with the same names from different classes:

class Car {
  #color;

  hasColor() {
    return #color in this;
  }
}

class House {
  #color;

  hasColor() {
    return #color in this;
  }
}

const car = new Car();
const house = new House();

console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false

7. at() Method for Indexing

We typically use square brackets ([]) in JavaScript to access the Nth element of an array, which is usually a simple process. We just access the N - 1 property of the array.

const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b

However, we have to use an index of arr.length - N if we want to access the Nth item from the end of the array with square brackets.

const arr = ['a', 'b', 'c', 'd'];

// 1st element from the end
console.log(arr[arr.length - 1]); // d

// 2nd element from the end
console.log(arr[arr.length - 2]); // c

The new at() method added in ES2022 lets us do this in a more concise and expressive way. To access the Nth element from the end of the array, we simply pass a negative value of -N to at().

const arr = ['a', 'b', 'c', 'd'];

// 1st element from the end
console.log(arr.at(-1)); // d

// 2nd element from the end
console.log(arr.at(-2)); // c

Apart from arrays, strings and TypedArray objects also now have at() methods.

const str = 'Coding Beauty';
console.log(str.at(-1)); // y
console.log(str.at(-2)); // t

const typedArray = new Uint8Array([16, 32, 48, 64]);
console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48

8. RegExp Match Indices

This new feature allows us to specify that we want the get both the starting and ending indices of the matches of a RegExp object in a given string.

Previously, we could only get the starting index of a regex match in a string.

const str = 'sun and moon';

const regex = /and/;

const matchObj = regex.exec(str);

// [ 'and', index: 4, input: 'sun and moon', groups: undefined ]
console.log(matchObj);

Now with ES13, we can specify a d regex flag to get the two indices where the match starts and ends.

const str = 'sun and moon';

const regex = /and/d;

const matchObj = regex.exec(str);

/**
[
  'and',
  index: 4,
  input: 'sun and moon',
  groups: undefined,
  indices: [ [ 4, 7 ], groups: undefined ]
]
 */
console.log(matchObj);

With the d flag set, the object returned will have an indices property that contains the starting and ending indices.

9. Object.hasOwn() Method

In JavaScript, we can use the Object.prototype.hasOwnProperty() method to check if an object has a given property.

class Car {
  color = 'green';
  age = 2;
}

const car = new Car();

console.log(car.hasOwnProperty('age')); // true
console.log(car.hasOwnProperty('name')); // false

But there are certain problems with this approach. For one, the Object.prototype.hasOwnProperty() method is not protected – it can be overridden by defining a custom hasOwnProperty() method for a class, which could have completely different behavior from Object.prototype.hasOwnProperty().

class Car {
  color = 'green';
  age = 2;

  // This method does not tell us whether an object of
  // this class has a given property.
  hasOwnProperty() {
    return false;
  }
}

const car = new Car();

console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false

Another issue is that for objects created with a null prototype (using Object.create(null)), trying to call this method on them will cause an error.

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;

// TypeError: obj.hasOwnProperty is not a function
console.log(obj.hasOwnProperty('color'));

One way to solve these issues is to use to call the call() method on the Object.prototype.hasOwnProperty Function property, like this:

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(Object.prototype.hasOwnProperty.call(obj, 'color')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // false

This isn’t very convenient. We can write our own reusable function to avoid repeating ourselves:

function objHasOwnProp(obj, propertyKey) {
  return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(objHasOwnProp(obj, 'color')); // true
console.log(objHasOwnProp(obj, 'name')); // false

No need for that though, as we can use the new built-in Object.hasOwn() method added in ES2022. Like our reusable function, it takes an object and property as arguments and returns true if the specified property is a direct property of the object. Otherwise, it returns false.

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;

console.log(Object.hasOwn(obj, 'color')); // true
console.log(Object.hasOwn(obj, 'name')); // false

10. Error Cause

Error objects now have a cause property for specifying the original error that caused the error about to be thrown. This adds additional contextual information to the error and assists in the diagnosis of unexpected behavior. We can specify the cause of an error by setting a cause property on an object passed as the second argument to the Error() constructor.

function userAction() {
  try {
    apiCallThatCanThrow();
  } catch (err) {
    throw new Error('New error message', { cause: err });
  }
}

try {
  userAction();
} catch (err) {
  console.log(err);
  console.log(`Cause by: ${err.cause}`);
}

11. Array Find from Last

In JavaScript, we can already use the Array find() method to find an element in an array that passes a specified test condition. Similarly, we can use findIndex() to find the index of such an element. While find() and findIndex() both start searching from the first element of the array, there are instances where it would be preferable to start the search from the last element instead.

There are scenarios where we know that finding from the last element might achieve better performance. For example, here we’re trying to get the item in the array with the value prop equal to y. With find() and findIndex():

const letters = [
  { value: 'v' },
  { value: 'w' },
  { value: 'x' },
  { value: 'y' },
  { value: 'z' },
];

const found = letters.find((item) => item.value === 'y');
const foundIndex = letters.findIndex((item) => item.value === 'y');

console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

This works, but as the target object is closer to the tail of the array, we might be able to make this program run faster if we use the new ES2022 findLast() and findLastIndex() methods to search the array from the end.

const letters = [
  { value: 'v' },
  { value: 'w' },
  { value: 'x' },
  { value: 'y' },
  { value: 'z' },
];

const found = letters.findLast((item) => item.value === 'y');
const foundIndex = letters.findLastIndex((item) => item.value === 'y');

console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

Another use case might require that we specifically search the array from the end to get the correct item. For example, if we want to find the last even number in a list of numbers, find() and findIndex() would produce a totally wrong result:

const nums = [7, 14, 3, 8, 10, 9];

// gives 14, instead of 10
const lastEven = nums.find((value) => value % 2 === 0);

// gives 1, instead of 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);

console.log(lastEven); // 14
console.log(lastEvenIndex); // 1

We could call the reverse() method on the array to reverse the order of the elements before calling find() and findIndex(). But this approach would cause unnecessary mutation of the array, as reverse() reverses the elements of an array in place. The only way to avoid this mutation would be to make a new copy of the entire array, which could cause performance problems for large arrays.

Also, findIndex() would still not work on the reversed array, as reversing the elements would also mean changing the indexes they had in the original array. To get the original index, we would need to perform an additional calculation, which means writing more code.

const nums = [7, 14, 3, 8, 10, 9];

// Copying the entire array with the spread syntax before
// calling reverse()
const reversed = [...nums].reverse();

// correctly gives 10
const lastEven = reversed.find((value) => value % 2 === 0);

// gives 1, instead of 4
const reversedIndex = reversed.findIndex((value) => value % 2 === 0);

// Need to re-calculate to get original index
const lastEvenIndex = reversed.length - 1 - reversedIndex;

console.log(lastEven); // 10
console.log(reversedIndex); // 1
console.log(lastEvenIndex); // 4

It’s in cases like where the findLast() and findLastIndex() methods come in handy.

const nums = [7, 14, 3, 8, 10, 9];

const lastEven = nums.findLast((num) => num % 2 === 0);
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);

console.log(lastEven); // 10
console.log(lastEvenIndex); // 4

This code is shorter and more readable. Most importantly, it produces the correct result.

Conclusion

So we’ve seen the newest features ES13 (ES2022) brings to JavaScript. Use them to boost your productivity as a developer and write cleaner code with greater conciseness and clarity.

How to Convert a Month Number to a Month Name in JavaScript

In this article, we’re going to learn how to get the name of a month by its position in the list of the 12 months using JavaScript.

Date toLocaleString() Method

To convert a month number to a month name, create a Date object with the given month, then call the toLocaleString() method on the Date with a specified locale and options.

For example, here is how we can get January for the number 1, February for 2, March for 3, and so on:

function getMonthName(monthNumber) {
  const date = new Date();
  date.setMonth(monthNumber - 1);

  return date.toLocaleString('en-US', { month: 'long' });
}

console.log(getMonthName(1)); // January
console.log(getMonthName(2)); // February
console.log(getMonthName(3)); // March

Our getMonthName() function takes a position and returns the name of the month with that position.

The setMonth() method sets the month of a Date object to a specified number.

Note

The value passed to setMonth() is expected to be zero-based. For example, a value of 0 represents January, 1 represents February, 2 represents March, and so on. This why we pass the value of 1 subtracted from the month number (monthNumber - 1) to setMonth().

We used the Date toLocaleString() method to get the name of the month of the date. toLocaleString() returns a string with a language-sensitive representation of a date.

This method has two parameters:

  1. locales: A string with a BCP 47 language tag, or an array of such strings. There are many locales we can specify, like en-US for US English, en-GB for UK English, and en-CA for Canadian English.
  2. options: An object used to adjust the output format of the date.

In our example, we pass en-US as the language tag to use US English, and we set a value of long to the month property of the options object to display the full month name.

We can pass an empty array ([]) as the first argument to make toLocaleString() use the browser’s default locale:

function getMonthName(monthNumber) {
  const date = new Date();
  date.setMonth(monthNumber - 1);

  // Using the browser's default locale.
  return date.toLocaleString([], { month: 'long' });
}

console.log(getMonthName(1)); // January
console.log(getMonthName(2)); // February
console.log(getMonthName(3)); // March

This is good for internationalization, as the output will vary depending on the user’s preferred language.

We can specify other values apart from long for the month property. For example, we can use short to abbreviate the month names to three letters:

function getMonthName(monthNumber) {
  const date = new Date();
  date.setMonth(monthNumber - 1);

  return date.toLocaleString('en-US', { month: 'short' });
}

console.log(getMonthName(1)); // Jan
console.log(getMonthName(2)); // Feb
console.log(getMonthName(3)); // Mar

Or we can use narrow to display only the first letter:

function getMonthName(monthNumber) {
  const date = new Date();
  date.setMonth(monthNumber - 1);

  return date.toLocaleString('en-US', { month: 'narrow' });
}

console.log(getMonthName(1)); // J
console.log(getMonthName(2)); // F
console.log(getMonthName(3)); // M

Note: Using narrow could lead to ambiguity for month names that start with the same letter in the language, e.g., January, June, and July.

For more information on the options you can set for toLocaleString(), check out this page in the MDN Docs.

Intl.DateTimeFormat Object

Using the toLocaleString() means that you have to specify a locale and options each time you want a language-sensitive string. To use the same settings to format multiple dates, we can use an object of the Intl.DateTimeFormat class instead.

For example:

function getTwoConsecutiveMonthNames(monthNumber) {
  const date1 = new Date();
  date1.setMonth(monthNumber - 1);

  const date2 = new Date();
  date2.setMonth(monthNumber);

  const formatter = new Intl.DateTimeFormat('en-US', { month: 'short' });

  // Format both dates with the same locale and options
  const firstMonth = formatter.format(date1);
  const secondMonth = formatter.format(date2);

  return `${firstMonth} & ${secondMonth}`;
}

console.log(getTwoConsecutiveMonthNames(1)); // Jan & Feb
console.log(getTwoConsecutiveMonthNames(2)); // Feb & Mar
console.log(getTwoConsecutiveMonthNames(3)); // Mar & Apr

How to Add Years to a Date in JavaScript

1. Date setFullYear() and getFullYear() Methods

To add years to a Date in JavaScript, call the getFullYear() method on the Date to get the year, then call the setFullYear() method on the Date, passing the sum of getFullYear() and the number of years to add as an argument, i.e., date.setFullYear(date.getFullYear() + years).

For example:

function addYears(date, years) {
  date.setFullYear(date.getFullYear() + years);
  return date;
}

// May 15, 2022
const date = new Date('2022-05-15T00:00:00.000Z');

const newDate = addYears(date, 3);

// May 20, 2025
console.log(newDate); // 2025-05-20T00:00:00.000Z

Our addYears() function takes a Date object and the number of years to add as arguments, and returns the same object with the newly added years.

The Date getFullYear() method returns a number that represents the year of a particular date.

The Date setFullYear() method sets the year of a date to a specified number.

Avoiding Side Effects

The setFullYear() method mutates the Date object it is called on. This introduces a side effect into our addYears() function. To avoid modifying the passed Date and create a pure function, make a copy of the Date and call setFullYear() on this copy, instead of the original.

function addYears(date, years) {
  const dateCopy = new Date(date);
  dateCopy.setFullYear(dateCopy.getFullYear() + years);
  return dateCopy;
}

// May 15, 2022
const date = new Date('2022-05-15T00:00:00.000Z');

const newDate = addYears(date, 3);

// May 20, 2025
console.log(newDate); // 2025-05-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-05-15T00:00:00.000Z

Functions that don’t modify external state (i.e., pure functions) tend to be more predictable and easier to reason about. This makes it a good practice to limit the number of side effects in your programs.

2. date-fns addYears() Function

Alternatively, we can use the pure addYears() function from the date-fns NPM package to quickly add years to a Date.

import { addYears } from 'date-fns';

// May 15, 2022
const date = new Date('2022-05-15T00:00:00.000Z');

const newDate = addYears(date, 3);

// May 20, 2025
console.log(newDate); // 2025-05-20T00:00:00.000Z

// Original not modified
console.log(date); // 2022-05-15T00:00:00.000Z

How to Remove a Class from the Body Element using JavaScript

To remove a class from the body element, call the classList.remove() method on the body element, e.g, document.body.classList.remove('the-class)'.

Here is some sample HTML:

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body class="class-1 class-2">
    <div>This is a div element.</div>

    <script src="index.js"></script>
  </body>
</html>

Here’s how we can remove the class class-1 from the body using JavaScript:

index.js

document.body.classList.remove('class-1');

We use the body property of the document to access the HTMLElement object that represents the document body.

The classList property returns a DOMTokenList object that represents the list of classes an element has.

The remove() method of the classList property takes a list of classes and removes them from an element.

After removing class-1, the document markup will look like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body class="class-2">
    <div>This is a div element.</div>

    <script src="index.js"></script>
  </body>
</html>

We can pass multiple arguments to the remove() method to remove more than one class from the body. For example, we can remove both class-1 and class-2 from the body using a single statement:

index.js

document.body.classList.remove('class-1', 'class-2');

This will be the resulting document markup:

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body>
    <div>This is a div element.</div>

    <script src="index.js"></script>
  </body>
</html>

If we pass a class that the element does not have, remove() ignores the class and does not throw an error.

Add class to body with JavaScript

To add a class to the body element instead, we can use the classList.add() method of the body object.

index.js

document.body.classList.add('class-3', 'class-4');

The add() method of the classList property takes a list of class names and adds them to an element.

This will be the resulting HTML after adding the two classes:

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body class="class-1 class-2 class-3 class-4">
    <div>This is a div element.</div>

    <script src="index.js"></script>
  </body>
</html>

add() prevents the same class from being added to an element multiple times, so a specified class is ignored if the element already has it.

How to Remove a DOM Element by its ID using JavaScript

In this article, we’re going to learn how to easily remove an element in the HTML DOM by its ID using JavaScript.

The Element remove() Method

To remove a DOM element by ID, use the getElementById() method to select the element with the ID, then call the remove() method on the element.

For example:

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body>
    <div class="box" id="box-1">This is a box</div>

    <script src="index.js"></script>
  </body>
</html>

Here’s how we can remove the element with the box-1 id:

index.js

const box = document.getElementById('box-1');
box.remove();

The getElementById() method takes a string and returns the element in the DOM with an ID that matches the string.

If there is no element with a matching ID, getElementByID() returns null.

index.js

const box = document.getElementById('box-5');
console.log(box); // null

We can use the optional chaining operator (?.) to call remove() to avoid causing an error if there is no DOM element with the ID.

Instead of causing an error, the optional chaining operator will prevent the method call and return undefined.

index.js

const box = document.getElementById('box-5');
box?.remove(); // no error thrown

How to Remove a DOM Element without Removing its Children

The remove() method removes a DOM element along with its children. What if want to keep the children of the element in the DOM?

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body>

    <div id="parent">
      <p>Child 1</p>
      <p>Child 2</p>
    </div>

    <script src="index.js"></script>
  </body>
</html>

To remove the div element with the ID parent but keep its children, we can call the replaceWith() method on the div, passing the children of the element as arguments.

index.js

const element = document.getElementById('parent');

element.replaceWith(...element.childNodes);

Now the markup of the document will look like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Coding Beauty Tutorial</title>
  </head>
  <body>
    <p>Child 1</p>
    <p>Child 2</p>

    <script src="index.js"></script>
  </body>
</html>

The childNodes property returns a list of the child nodes of an element. We use it to get the children of the element.

The replaceWith() method replaces an element in the DOM with a set of Node or string objects. We call it on the element to replace it with the children.

How to Check if a String is Empty in JavaScript

1. Comparing the String with an Empty String

To check if a string is empty in JavaScript, we can compare the string with an empty string ('') in an if statement.

For example:

function checkIfEmpty(str) {
  if (str === '') {
    console.log('String is empty');
  } else {
    console.log('String is NOT empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty

To treat a string containing only whitespace as empty, call the trim() method on the string before comparing it with an empty string.

function checkIfEmpty(str) {
  if (str.trim() === '') {
    console.log('String is empty');
  } else {
    console.log('String is NOT empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty
const str3 = '   '; // contains only whitespace

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty
checkIfEmpty(str3); // outputs: String is empty

The String trim() method removes all whitespace from the beginning and end of a string and returns a new string, without modifying the original.

const str1 = '  bread  ';
const str2 = '   milk tea    ';

console.log(str1.trim()); // 'bread'
console.log(str2.trim()); // 'milk tea'

Tip

Trimming a string when validating required fields in a form helps ensure that the user entered actual data instead of just whitespace.

How to Check if a String is Empty, null, or undefined

Depending on your scenario, you might want to consider that the string could be a nullish value (null or undefined). To check for this, use the string if statement directly, like this:

function checkIfEmpty(str) {
  if (str) {
    console.log('String is NOT empty');
  } else {
    console.log('String is empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty
const str3 = null;
const str4 = undefined;

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty
checkIfEmpty(str3); // outputs: String is empty
checkIfEmpty(str4); // outputs: String is empty

If the string is nullish or empty, it will be coerced to false in the if statement. Otherwise, it will be coerced to true.

To remove all whitespace and also check for a nullish value, use the optional chaining operator (?.) to call the trim() method on the string before using it in an if statement.

function checkIfEmpty(str) {
  if (str?.trim()) {
    console.log('String is NOT empty');
  } else {
    console.log('String is empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty
const str3 = null;
const str4 = undefined;
const str5 = '    '; // contains only whitespace

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty
checkIfEmpty(str3); // outputs: String is empty
checkIfEmpty(str4); // outputs: String is empty
checkIfEmpty(str5); // outputs: String is empty

The optional chaining operator lets us call the trim() method on a null or undefined string without causing an error. Instead, it prevents the method call and returns undefined.

const str1 = null;
const str2 = undefined;

console.log(str1?.trim()); // undefined
console.log(str2?.trim()); // undefined

2. Comparing the Length of the String with 0

Alternatively, we can access the length property of a string and compare its value with 0 to check if the string is empty.

function checkIfEmpty(str) {
  if (str.length === 0) {
    console.log('String is empty');
  } else {
    console.log('String is NOT empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty

To check for strings containing only whitespace with this approach, we would also call the trim() method before comparing the length of the trimmed string with 0.

function checkIfEmpty(str) {
  if (str.trim().length === 0) {
    console.log('String is empty');
  } else {
    console.log('String is NOT empty');
  }
}

const str1 = 'not empty';
const str2 = ''; // empty
const str3 = '   '; // contains only whitespace

checkIfEmpty(str1); // outputs: String is NOT empty
checkIfEmpty(str2); // outputs: String is empty
checkIfEmpty(str3); // outputs: String is empty