You’ve heard of the FAQ, which is typically a list of frequently asked questions on some topic or another. A twist on that idea, the FSS—for frequently sought solutions—lists solutions to some of the most common pleas for help. These tend to go beyond “newbie” questions and address real-life issues that bedevil programmers.

Here are 10 issues that come up again and again for developers working with JavaScript, with quick tips and code samples to help you resolve them.

1. Doing things with arrays

One thing programmers have to do all the time is manipulate arrays of data. This data can be objects, numbers, or strings. You get it from all kinds of places and you do all kinds of things with it: order it, organize it, break it into smaller chunks, and so on.

There are many ways to accomplish the things you need to do with arrays, including classic imperative loops. There isn’t really a right way. However, modern JavaScript gives you a set of incredibly handy functional operations that often provide a concise and streamlined way to do what needs doing. You just have to keep them in mind and know which functional operation to reach for when the time comes.

Consider this array:


const products = [
  { id: 1, name: "Apple", price: 1.99, inStock: true },
  { id: 2, name: "Banana", price: 0.79, inStock: false },
  { id: 3, name: "Orange", price: 2.49, inStock: true },
];

If we wanted to filter for only products in stock and sort them by ascending price, we could do this:


const availableProducts = products.filter(product => product.inStock)
  .sort((a, b) => a.price - b.price);

availableProducts now holds only those objects where inStock is true, and the list is sorted by price. The methods filter and sort are both built-in and take functions as arguments. (These are “higher-order functions,” a hallmark of functional programming.)

Each functional argument takes the element(s) to operate on and then does its work based on that. In the case of filter, if the function returns true, the element is kept in the resulting array. In sort(), two arguments are provided as the algorithm moves over the array. If the result is negative, the first item is sorted first and vice versa. (If 0 is returned, the items are equal.)

2. Manipulating the DOM

Although Reactive frameworks are often used for working on the DOM (the document object model that represents the user interface and lets you change it) developers still need to directly interact with the DOM using JavaScript.

DOM manipulation boils down to two basic things: reacting to events and changing elements and properties. Consider this example:





  

Welcome to our website!

Here we have a simple HTML page, with a title (h1) and a button (button). It creates a DOM tree where the

and elements are nested inside the . Also in there is the tag that executes some JavaScript.

The JavaScript grabs the button element by ID, using the document.getElementById("change-button") function.

On the button, we set an event listener using addEventListener. This is the fundamental mechanism for adding reactivity to a page. There are many event types. In our case, we want to respond to the button click using "click". The second argument lets us provide a callback function.

The callback function receives a single argument, which we name event. It has several properties we can use but the main one we want is target. That holds the element that was clicked. We use it to change the button style color to red.

To finish, we grab the h1 heading element by ID and change its text. The text and color changes are examples of using DOM element attributes.

3. Asynchronous programming

Modern JavaScript is good at asynchronous programming. It’s a good thing, too, because you have to do it a lot. The three main mechanisms for asynchronous programming are callbacks, promises, and async/await.

Callbacks are traditional:


let myCallback = function(){
  console.log(“I was called after one second.”);
}

setTimeout(myCallback, 1000);

This lets us run the myCallback function asynchronously, in this case, after 1,000 milliseconds. Here’s how we’d do the same thing using a Promise:


function waitOneSecond() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("I was called after one second.");
    }, 1000);
  });
}

waitOneSecond()
  .then(message => console.log(message))
  .catch(error => console.error(error));

We still have an asynchronous operation, and in fact, an asynchronous callback. But now it’s wrapped in a Promise. This lets us call the then and catch methods to deal with the results without nested callbacks.

Async/await blocks make promises simpler and more declarative. They let you write code to use promises like this:


async function waitOneSecondAsync() {
  try {
    new Promise(resolve => setTimeout(() => console.log("I was called after one second."), 1000));
  } catch (error) {
    console.error(error);
  }
}

console.log(“Before”);
await waitOneSecondAsync();
console.log(“after”);

If you remove the await from this code, the “before” and “after” log outputs will happen before the timeout. The await lets you pause until the async operation is done—similar to using a Promise with a then().

4. Error handling

Code can raise an exception (also known as throwing an error) at any time to indicate a problem:


throw new Error("Something is not right here.")

This will cause the normal flow of execution to cease, and that call stack to “unwind”. If the stack includes try/catch blocks, the first one encountered will handle the error. Here’s a compact example:


try{ 
  throw new Error("Something is not right here.") 
} catch(e) { 
  console.log("Got an error: " + e);
}

This will print: Got an error: Error: Something is not right here.

More elaborate error handling is possible, including attempting to recover, retry, or any other number of strategies given the circumstances. We can also define a finally block, which will be called if there is an error or not:


try{ 
  throw new Error("Something is not right here.") 
} catch(e) { 
  console.log("Got an error: " + e);
} finally {
  console.log(“No matter what, I’ll print.”);
}

When using asynchronous operations with promises, we can use catch() and finally() in a similar fashion. Let’s continue with our timeout example:


function waitOneSecond() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("Network error!"));  
    }, 1000);
  });
}

waitOneSecond()
  .then(message => console.log(message))  
  .catch(error => console.error("Error:", error.message))   .finally(() => console.log("This always executes, regardless of errors."));  

In this case, the catch() and finally() blocks will always execute, because an error is always thrown. In real code, when normal execution doesn’t throw an error, the catch call won’t happen.

5. Getting started with objects

Objects are a central part of programming JavaScript. JavaScript even has a built-in notation for describing them, JSON:


let campingSpot = {
  name:  “Willow Creek”,
  location: “Big Sur”
}

Here’s how to access the properties on the object:


console.log(“We’re going camping at “ + campingSpot.name);

Objects in JavaScript are not limited to JSON. We can also define behavior in the form of functions (called methods when on an object):


let campingSpot = {
  name:  “Willow Creek”,
  describeWater: function(){
    console.log(“Very cold”);
  }
}

We are not limited to one-off objects, either. We can also define classes of objects:


class CampingSpot {
  constructor(name, location) {
    this.name = name;
    this.location = location;
  }
    describeWater() {
      console.log("The water at " + this.name + " is very cold.");
    }
}

Now we can create instances of the CampingSpot object at will:


let willowCreek = new CampingSpot("Willow Creek", "Big Sur");
let sunsetStateBeach = new CampingSpot(“Sunset State Beach”, “Santa Cruz”);

6. Using remote APIs

Accessing APIs hosted on services is another common need in JavaScript programs. APIs provide access to external data and functionalities. Developers often seek solutions to fetch data from remote APIs, parse responses, and integrate them into their applications.

Fortunately, modern JavaScript includes the Fetch API in both client and server environments. This is a simple and direct way to make HTTP calls. For example, here’s how we’d get the list of Star Wars movies from the SWAPI service:


async function getStarWarsFilms() {
  try {
    const response = await fetch('https://swapi.dev/api/films');
    if (!response.ok) {
      throw new Error(`Error fetching Star Wars films: ${response.status}`);
    }
    const data = await response.json();
    console.log(data.results); 
  } catch (error) {
    console.error("Error:", error);
  }
}

getStarWarsFilms();

Because this is a GET request, we can just use fetch('https://swapi.dev/api/films'). Notice we use await, which I introduced earlier. That lets us pause while the request goes out and the response comes back.

We use the response object to determine if the request was good (an HTTP 200 response), using response.ok.

7. String manipulation

Strings are fundamental and used in all kinds of situations. Consider the following string:


const taoTeChingVerse1 = 
  `The Tao that can be told is not the eternal Tao. 
  The name that can be named is not the eternal name. 
  The nameless is the beginning of heaven and earth. 
  The named is the mother of all things,`;

Let’s say we wanted only the first line of the first verse:


const firstLine = taoTeChingVerse1.slice(0, 48);

This says: Give us the substring between the first character (0) until the 48th character, inclusive.

To search for the first occurrence of the word “Tao”, enter:


taoTeChingVerse1.indexOf("Tao"); // returns 4

Now, if you want to replace words, you use some simple regex. Here, we replace all occurrences of “told” with “spoken”:


const newText = text.replace(/told/g, "spoken");

The slashes indicate a regular expression, which we match on “told.” The suffix g indicates “global,” meaning all occurrences. The second argument to replace() is the token to swap in. (We wind up with “The Tao that can be spoken is not the eternal Tao.”)

If we need to concatenate two strings, a simple plus (+) operator will do the trick:


let fullVerse = taoTeChingVerse1 + “Having both but not using them, Think of them as the constant.”);

And, you can always count the string length with:


fullVerse.length; // return 261

8. Converting JSON objects to strings

Another common need is to take an actual JSON object and make it a string, or vice versa. Here’s how to take a live JSON object and make it a string:


let website = {
  name: “InfoWorld”,
  url: “www.infoworld.com”
}

let myString = JSON.stringify(website);

And here’s how to take the string and return it to an object:


JSON.parse(myString);

9. Simple date operations

There’s a lot you can do (and must do) with JavaScript’s built-in Date object.

To start, you can get today’s date like so:


const today = new Date();

And get its constituent parts like this:


console.log(today.getFullYear());  // Get the year (e.g., 2024)
console.log(today.getMonth());    // Get the month (0-indexed, e.g., 4 for May)
console.log(today.getDate());     // Get the day of the month (e.g., 21)
console.log(today.getHours());    // Get hours (e.g., 13 for 1 PM)
console.log(today.getMinutes());  // Get minutes (e.g., 27)
console.log(today.getSeconds());  // Get seconds (e.g., 46)

Here’s how to get seven days in the future:


date.setDate(date.getDate() + 7);

10. Creating, finding, and counting numbers

JavaScript today is pretty good with numbers. It natively handles most numbers and offers a built-in library, Math, for extra power.

You can create numbers:


let age = 30;
let pi = 3.14159;
let billion = 1000000000;

Or convert from a string:


let convertedNumber = Number(“42”);

Normal operations behave in obvious ways:


let addition = pi + 3; // addition now equals 6.14159

You can round numbers quickly:


Math.ceil(pi); // round to nearest upper integer (4)
Math.floor(pi); // round to lowest int (3)

Find the largest number:


Math.max(100, 5, 10, 73);  // returns 100

If you start with an array, you can use the spread operator:


let numbers = [100, 5, 10, 73];
Math.max(...numbers); // returns 100

Finally, here’s how to check for evenness:


let isEven = 10 % 2 === 0; // true (checks if remainder is 0)