Challenges

Select a challenge to start coding.

The Default Greeting

EASY

Let's practice using the binary Logical OR || to provide a "fallback" value. This is its most common use case for this operator.

Write a function greet(name) that takes a single name string as an argument.

  • If a name is provided (e.g., "Alice"), it should return "Hello, Alice!".

  • If the name is not provided (it will be undefined) or if it's an empty string (""), it should return "Hello, Guest!".

Constraint: You cannot use an if statement for this.

Test Cases:

  • greet("Alice") should return "Hello, Alice!"

  • greet("") should return "Hello, Guest!"

  • greet(undefined) should return "Hello, Guest!"

💡 The 'Syntax Nudge'

This is the perfect place to use the Logical OR (||) operator.

Remember its core rule: valueA || valueB The JavaScript engine first looks at valueA.

  • If valueA is "truthy" (any string with content, any number not 0, true, objects, arrays), it just returns valueA and stops.

  • If valueA is "falsy" (specifically undefined, null, "" (empty string), 0, false, NaN), it discards it and returns valueB instead.



We can think of operators in terms of how many "things" (we call them operands) they work on.

  • Unary Operator: Works on one thing.

    • ! (Logical NOT): !isReady (flips isReady from true to false)

    • typeof: typeof 10 (tells you the type is "number")

    • i++ (Increment): Works on the single variable i.

  • Binary Operator: Works on two things. This is most of what you use every day.

    • 1 + 2 (The + works on 1 and 2)

    • x > y (The > works on x and y)

    • a && b (Logical AND)

    • a || b (Logical OR - the one that confused you!)

  • Ternary Operator: The one and only! It works on three things.

    • (condition ? valueIfTrue : valueIfFalse)

Binary operatorFallback values

The Light Switch

EASY

Write a function toggleSwitch(isOn) that takes a single boolean value (true or false) representing the state of a light switch. Your function should return the new state of the switch.

Test Cases:

  • toggleSwitch(true) should return false

  • toggleSwitch(false) should return true

💡 The 'Syntax Nudge'

This one is a direct application of the operator. How can you use ! on the isOn argument to return the opposite value?



The Logical NOT ! is a unary operator because it only works on one operand (the value right after it).

Its job is simple:

  1. It takes any value.

  2. It coerces (converts) that value into its "truthy" or "falsy" boolean equivalent.

  3. It flips that boolean.

  • !true becomes false

  • !false becomes true

  • !"hello" (a "truthy" string) becomes false

  • !0 (a "falsy" number) becomes true

Control Flow BasicsUnary Operator

The "Empty" Checker

EASY

Let's write a function isEmpty(value) that checks if a value is "empty." For our purposes, "empty" means it's one of the common falsy values:

  • undefined

  • null

  • 0

  • "" (empty string)

  • false

Your function should return true if the value is falsy (empty) and false if the value is truthy (not empty).

Test Cases:

  • isEmpty("") should return true

  • isEmpty(0) should return true

  • isEmpty(undefined) should return true

  • isEmpty("hello") should return false

  • isEmpty(42) should return false

  • isEmpty(true) should return false

💡 The 'Syntax Nudge'

Think about the two-step process of the ! operator:

  1. It coerces the value to its boolean equivalent. ("hello" becomes true, "" becomes false).

  2. It flips that boolean.

How can you use ! to achieve the desired outcome? You might need to use it more than once. Think about what !value would give you, and what !!value would give you. Which one gets you closer to the goal?

Unary OperatorTruthy and Falsy ValuesBoolean Logic

The "Truthy" Checker

EASY

Write a function isTruthy(value) that takes any value.

  • It should return true if the value is truthy.

  • It should return false if the value is falsy.

Constraint: You cannot use an if statement.

Test Cases:

  • isTruthy("hello") should return true

  • isTruthy(42) should return true

  • isTruthy(true) should return true

  • isTruthy("") should return false

  • isTruthy(0) should return false

  • isTruthy(undefined) should return false

💡 The 'Syntax Nudge'

This is the classic use case for the double bang (!!) operator. How can you use it to "normalize" the input value into its pure boolean form?



If ! means "take this value, find its truthiness, and flip it," then !! simply means "do that twice."

  • !!value = !(!value)

Why on earth would you do this? It's used to normalize any value into a "pure" boolean. It's a very common way to answer the question, "Does this value have anything in it?"

Let's trace it with "hello":

  1. !"hello" (truthy) becomes false

  2. !false (the second !) becomes true So, !!"hello" = true

Let's trace it with 0:

  1. !0 (falsy) becomes true

  2. !true (the second !) becomes false So, !!0 = false

The !! operator is a concise way of forcing any value to its simple true or false equivalent.

Unary OperatorTruthy and Falsy ValuesType Coercion

The Price Checker

EASY

Let's write a function getTicketPrice(age) that takes a person's age.

  • If the person is 18 or older, the price is $20.

  • If the person is younger than 18, the price is $10.

Constraint: You must use the ternary operator to solve this.

Test Cases:

  • getTicketPrice(30) should return $20

  • getTicketPrice(18) should return $20

  • getTicketPrice(10) should return $10

💡 The 'Syntax Nudge'

Your "condition" will be age >= 18. Your "valueIfTrue" will be $20. Your "valueIfFalse" will be $10.

How do you assemble these three parts using the ? : syntax?


The Ternary (? :)

This operator is a "ternary" because it works on three operands. It's our final operator in this bootcamp.

It's just a clean, one-line shortcut for a simple if...else statement.

The if...else way:
let message;

if (age >= 21) {

message = "You may enter.";

} else {

message = "You are too young.";

}

The Ternary way:
let message = (age >= 21) ? "You may enter." : "You are too young.";

The syntax is: (condition) ? valueIfTrue : valueIfFalse

Control Flow BasicsTernary operatorConditional Logic

The Key Collector

EASY

Write a function collectKeys(obj) that takes an object. Return an array of all the keys in that object, but converted to uppercase.

  • Input: { id: 1, city: "NY" }

  • Step 1: Get the keys (array).

  • Step 2: Map over them to uppercase.

  • Return: ["ID", "CITY"]


Explanation of object Iteration tools:
Here is the problem: Arrays are easy to loop over. Objects are not.


const user = { name: "Alice", age: 25, role: "Admin" };

// user.map(...) // ❌ CRASH! Objects don't have .map()

// user.forEach(...) // ❌ CRASH!

To loop over an object, we use a "Static Method" to convert the Object into an Array. The first tool is: Object.keys(obj)

It returns an array of the property names (keys).

const keys = Object.keys(user);

// ["name", "age", "role"]

// NOW you can use .map() or .forEach() on 'keys'!

String ManipulationArray MethodsObject Iteration

The Nested Ternary

EASY

Let's write a function getAccessLevel(role) that takes a role string.

  • If the role is "admin", return "Full Access".

  • If the role is "editor", return "Limited Access (Editing)".

  • For any other role (including undefined or ""), return "Guest Access".

Constraint: You must solve this with a single return statement using only ternary operators. No if/else.

Test Cases:

  • getAccessLevel("admin") should return "Full Access"

  • getAccessLevel("editor") should return "Limited Access (Editing)"

  • getAccessLevel("user") should return "Guest Access"

  • getAccessLevel("") should return "Guest Access"

💡 The 'Syntax Nudge'

This is what separates a novice from a master. The valueIfFalse part of a ternary operator doesn't just have to be a simple value... it can be another ternary operator.

Think about it like this: return (condition1) ? "valueA" : (condition2 ? "valueB" : "valueC")

How can you "nest" your logic to check for "admin", then "editor", then everything else?

Control Flow BasicsTernary operatorConditional Logic

Reverse a String

EASY

Write a function called reverseString that takes a single string as an argument and returns a new string with the characters in the reverse order.

For example:

  • reverseString("hello") should return "olleh"

  • reverseString("JavaScript") should return "tpircSavaJ"

Now, for your first nudge... 💡

The 'Syntax Nudge'

A very clean way to solve this involves changing the string into a different data type that's easier to re-order, and then changing it back. I suggest you research these three highly useful JavaScript methods on MDN (the Mozilla Developer Network):

  • String.prototype.split()

  • Array.prototype.reverse()

  • Array.prototype.join()

String ManipulationArray Methods

Palindrome Checker

EASY

A palindrome is a word, phrase, or sequence that reads the same backward as forward. For example, "racecar" or "madam".

Write a function isPalindrome(str) that takes a string and returns true if the string is a palindrome and false if it is not.

For this challenge, we should ignore punctuation, spaces, and casing. So, "A man, a plan, a canal: Panama" should return true.

Here are some test cases:

  • isPalindrome("racecar") should return true

  • isPalindrome("hello") should return false

  • isPalindrome("A man, a plan, a canal: Panama") should return true

You already know how to reverse a string, which is half the battle! The other half is cleaning up the input string first.

💡 The 'Syntax Nudge'

To solve this, you'll need to "sanitize" the input string before you check it. I suggest you research these two tools:

  • String.prototype.toLowerCase(): How can you make sure "T" is treated the same as "t"?

  • String.prototype.replace(): This method is incredibly powerful. Specifically, look up how to use it with a bit of RegEx (Regular Expressions) to remove characters you don't want. A good RegEx to search for would be one that finds all non-alphanumeric characters.

String ManipulationArray MethodsRegular expressions

Anagram Checker

EASY

An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. For example, "listen" is an anagram of "silent".

Write a function isAnagram(str1, str2) that takes two strings and returns true if the second string is an anagram of the first, and false otherwise.

  • Like before, the comparison should be case-insensitive.

  • Spaces and punctuation should be considered, so "Dormitory" is an anagram of "dirty room", but you'll need to remove the space.

Test cases:

  • isAnagram("anagram", "nagaram") should return true

  • isAnagram("rat", "car") should return false

  • isAnagram("Dormitory", "dirty room") should return true

💡 The 'Syntax Nudge'

You could solve this by sanitizing and sorting the strings, but let's try a more performant approach that doesn't require sorting. This introduces the Frequency Counter pattern.

The core idea is to count how many times each character appears in the first string, and then see if the second string matches that count exactly. An object {} is the perfect tool for this.

I suggest you research:

  • How to loop through a string using a for ... of loop.

  • How to add and access properties in a JavaScript object (e.g., myObject[key]).

  • A clever trick for incrementing a count in an object: charMap[char] = (charMap[char] || 0) + 1;. Think about why the || 0 part is necessary.

String ManipulationIterations and Loops

Ransom Note

EASY

Write a function canWriteRansomNote(note, magazine) that takes two strings, note and magazine. Your function should return true if the note can be constructed by cutting out letters from the magazine and false otherwise.

  • Each letter in the magazine can only be used once.

  • The comparison is case-sensitive (this makes it a bit easier!).

Test Cases:

  • canWriteRansomNote("a", "b") should return false

  • canWriteRansomNote("aa", "ab") should return false

  • canWriteRansomNote("aa", "aab") should return true

  • canWriteRansomNote("find me", "i need to find a new me") should return true

Think about the logic we just used. Which string should you build the 'Character Map' from? And which string should you check against the map?

💡 The 'Syntax Nudge'

You have all the tools you need! The logic is identical, but the order is important.

  • You'll need to build a frequency map (just like charMap) of the letters you have available. Which string represents the letters you have?

  • Then, you'll loop through the string you're trying to build and check against that map.

  • You'll use the same for...of loop and the same Bracket Notation (map[char]) to solve this.

String ManipulationIterations and LoopsFrequency Counter Pattern

The Inventory Aggregator

MEDIUM

Write a function groupInventory(items) that takes an array of item objects. Each item has a name and a category. Your function should return a single object where the keys are the categories, and the values are arrays of item names belonging to that category.

Constraint: You must use the Array.prototype.reduce() method. Do not use a for loop or forEach.

Test Cases:
const items = [

{ name: "Apple", category: "Fruit" },

{ name: "Carrot", category: "Vegetable" },

{ name: "Banana", category: "Fruit" },

{ name: "Broccoli", category: "Vegetable" }

];

groupInventory(items);

Should return:

{

Fruit: ["Apple", "Banana"],

Vegetable: ["Carrot", "Broccoli"]

}

groupInventory([]); // Should return {}

ReduceObjects and Properties