5 JavaScript Challenges to Sharpen Your Coding Skills

August 26, 2025
10 read

If you want to move beyond the basics of JavaScript and actually think like a developer, the best way is to solve real problems instead of just reading definitions. Documentation and tutorials are useful, but nothing improves your fundamentals more than tackling coding tasks where you apply logic, debug mistakes, and find out how JavaScript behaves in different scenarios.

In this article, I’ll walk you through five intermediate-level problems that are highly practical. These examples cover arrays, objects, promises, string operations, and recursion. Each problem includes code, test cases, and an easy-to-follow explanation. By the end, you’ll see how common JS features like reduce(), Promise.all() and map() a ctually work in action.

1. Manipulating Arrays the Smart Way

Problem: Take an array of numbers. Double all even numbers and halve all odd numbers.


function modifyArray(arr) {
return arr.map(num => (num % 2 === 0 ? num * 2 : num / 2));
}

// Test cases
console.log(modifyArray([2, 3, 4, 5]));
// [4, 1.5, 8, 2.5]

console.log(modifyArray([10, 15, 20, 25]));
// [20, 7.5, 40, 12.5]

Explanation:

  1. map() : loops through each element and returns a new array.
  2. For every number, we check if it’s even(num % 2 === 0)
  3. If yes, multiply by 2; if not, divide by 2.

This is a simple example, but it teaches you two things: conditional logic inside map() and the idea of returning transformed arrays without modifying the original one.

2. Turning Arrays into Objects

Problem: You have an array of objects. Transform it into one big object, where each object can be accessed by a chosen key (for example, id).


function arrayToObject(arr, key = 'id') {
return arr.reduce((acc, obj) => {
acc[obj[key]] = obj;
return acc;
}, {});
}

// Test cases
const input = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];

console.log(arrayToObject(input));
// { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } }

Explanation:

  1. .reduce() lets you accumulate results as you loop through the array.
  2. In each step, we add a property to the final object where the key comes from the object’s id.

👉 This technique is widely used in real-world apps where you need fast lookups by ID or username.

3. Handling Multiple Promises

Problem: Given a list of URLs, fetch data from all of them and return their JSON results.


async function fetchData(urls) {
const promises = urls.map(url => fetch(url).then(res => res.json()));
return Promise.all(promises);
}

// Test cases
const urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2'
];

fetchData(urls).then(data => console.log(data));

📝 Explanation:

  1. Each fetch() returns a promise, so we use .map() to create an array of promises.
  2. Promis.all() waits for all of them to resolve and returns their results in order.
  3. Since the function is async, it itself returns a promise, making it easy to chain further.

👉 This is how you’d actually fetch multiple APIs in a dashboard or news application.

4. String Compression

Problem: Compress a string so that repeated characters are replaced by the character followed by its count.


function compressString(str) {
let result = '';
let count = 1;

for (let i = 0; i < str.length; i++) {
if (str[i] === str[i + 1]) {
count++;
} else {
result += str[i] + count;
count = 1;
}
}
return result;
}

// Test cases
console.log(compressString('aaabbcccaa'));
// "a3b2c3a2"

console.log(compressString('abc'));
// "a1b1c1"

📝 Explanation:

  1. We loop through the string and count how many times the same character appears in a row.
  2. When the character changes, we add the character + its count to the result.

👉 This logic is the base of Run Length Encoding (RLE), a simple compression algorithm used in real systems.

5. Flattening Nested Arrays

Problem: Take a deeply nested array and flatten it into a single-level array.


function flattenArray(arr) {
return arr.reduce((flat, item) => {
return flat.concat(Array.isArray(item) ? flattenArray(item) : item);
}, []);
}

// Test cases
console.log(flattenArray([1, [2, [3, 4, [5]]]]));
// [1, 2, 3, 4, 5]

console.log(flattenArray([[1, 2], [3, [4, 5]]]));
// [1, 2, 3, 4, 5]

📝 Explanation:

  1. If an element is an array, we call the function again (recursion).
  2. Otherwise, we simply add the value to the flat array.
  3. Over time, every nested structure gets merged into one clean array.

👉 This is the same concept behind the new .flat() method in modern JavaScript, but writing it manually helps you understand recursion better.

Final Thoughts

These five challenges may look simple at first, but they represent the building blocks of countless real-world applications. From transforming data to handling APIs and compressing strings, you’ll notice that these are the same problems developers face every day.

By practicing:

  1. You get comfortable with higher-order functions like map() and reduce().
  2. You strengthen your understanding of asynchronous code with promises.
  3. You get a taste of recursion, which is critical for solving nested structures.

👉 Instead of memorizing syntax, try building mini-projects with these concepts. For example:

  1. Use array manipulation in a to-do list app.
  2. Apply object transformation to manage users in a chat app.
  3. Practice promises by fetching live weather data.
  4. Use string compression for a simple text editor.
  5. Try flattening arrays when working with nested categories in e-commerce.

The more you solve, the more confident you’ll feel. And the best part? These skills are exactly what interviewers test for in coding rounds.

So next time JavaScript starts to feel boring, pick a problem like these and code your way to mastery.

Sponsored Content

Comments (0)

Leave a Comment

Login Required

You need to be logged in to post a comment.

Loading comments...