Author: Amber Colvin

  • JavaScript API Call with fetch(): GET and JSON POST Requests

    JavaScript API Call with fetch(): GET and JSON POST Requests

    Use fetch() to make a JavaScript API call with the browser’s built-in, promise-based request function. This guide shows how to call an API in JavaScript with async/await for GET and JSON POST requests.

    An API call from JavaScript returns a promise, so await keeps the control flow readable while the browser waits for a response.

    Build a JavaScript API call with fetch()

    fetch() starts a request and returns a promise that resolves to a Response object. The complete async GET function below adds URL parameters, checks response.ok before parsing, and rethrows failures so calling code can handle them.

    GET example: async function getUsers(limit, role) { try { const params = new URLSearchParams({ limit: String(limit), role }); const url = “https://api.example.com/users?” + params.toString(); const response = await fetch(url); if (!response.ok) { throw new Error(“GET failed: ” + response.status); } return await response.json(); } catch (error) { console.error(“Could not load users:”, error); throw error; } }

    GET is the default HTTP method, so this request does not need an options object. await fetch(url) waits for the response promise, while await response.json() waits for the separate promise that parses the response body.

    How to call an API in JavaScript with GET parameters

    Place query parameters after a question mark in the URL. URLSearchParams creates that query string and encodes spaces and special characters safely. In the example, limit and role become parameters such as ?limit=10&role=admin.

    Call the function with getUsers(10, “admin”). To set the method explicitly, pass a second argument to fetch(): fetch(url, { method: “GET” }). The server’s status is available through response.status, while response.ok is true only for successful 2xx responses.

    Send JSON with POST requests and headers

    Use POST when the request sends data to the server. Set the method to “POST”, identify the body as JSON with a Content-Type header, and convert the JavaScript object with JSON.stringify() before sending it.

    JSON POST example: async function createUser(user) { try { const response = await fetch(“https://api.example.com/users”, { method: “POST”, headers: { “Content-Type”: “application/json”, “Accept”: “application/json” }, body: JSON.stringify(user) }); if (!response.ok) { throw new Error(“POST failed: ” + response.status); } return await response.json(); } catch (error) { console.error(“Could not create user:”, error); throw error; } }

    For example, pass an object with createUser({ name: “Ada”, email: “[email protected]” }). The request headers tell the server how to interpret the body and what response format the client prefers.

    Handle network, HTTP, and parsing errors

    Handle these failures separately:

    • Network errors: fetch() rejects when the request cannot be completed, such as when the network is unavailable or the request is blocked. The surrounding try…catch handles that rejection.
    • HTTP errors: A 404 or 500 response does not automatically reject the fetch promise. The promise resolves normally, so check response.ok and throw an error when it is false.
    • Parsing errors: response.json() returns a promise and rejects when the body is not valid JSON. Using return await response.json() inside the try block sends that failure to catch.

    If an endpoint returns an empty or non-JSON body, use await response.text() instead of response.json().

  • Sort in JavaScript: Ascending and Descending Arrays

    Sort in JavaScript: Ascending and Descending Arrays

    sort in JavaScript uses the Array.prototype.sort() method. By default, it converts array elements to strings and orders their UTF-16 values, so string arrays often sort as expected but number arrays can produce surprising results.

    For numbers, pass a comparator: (a, b) => a – b sorts ascending, while (a, b) => b – a sorts descending. The same comparator pattern works for numeric properties on objects.

    How does sort in JavaScript behave by default for strings and numbers?

    Without a comparator, sort() compares string representations. For example, [‘pear’, ‘apple’, ‘orange’].sort() returns [‘apple’, ‘orange’, ‘pear’]. Uppercase and lowercase characters can appear in separate groups because their character codes differ.

    The same rule causes numeric errors. [10, 2, 1, 21].sort() becomes [1, 10, 2, 21], because the values are compared as ’10’, ‘2’, ‘1’, and ’21’. Use a numeric comparator whenever the array contains numbers. Default sorting is appropriate only when its string-based ordering matches the intended result.

    How does a JavaScript numeric sort handle ascending and descending values?

    A comparator receives two elements, a and b. A negative return value places a before b; a positive value places b first; zero treats them as equal. This return-value contract lets JavaScript calculate numeric order directly.

    For ascending order, subtract the second value from the first:

    const ascending = numbers.sort((a, b) => a – b);

    If a is smaller than b, the result is negative, so a moves earlier. If a is larger, the result is positive, so it moves later. This is the standard JavaScript numeric sort for low-to-high values.

    To sort descending in JavaScript, reverse the subtraction:

    const descending = numbers.sort((a, b) => b – a);

    Now a larger value produces a negative result and moves toward the start of the array. Both calls mutate numbers; use a copy when the original order matters.

    How do you sort objects by a property?

    For objects, the comparator should read the property used for ordering. This example sorts players by a numeric score from lowest to highest:

    players.sort((a, b) => a.score – b.score);

    For highest to lowest, switch the operands:

    players.sort((a, b) => b.score – a.score);

    String properties need a string comparator. For example, players.sort((a, b) => a.name.localeCompare(b.name)) orders names alphabetically according to the available locale rules. For descending names, compare b.name with a.name. Keep the property types consistent so the comparator returns reliable results.

    What changes when sort() mutates, and when should you use toSorted()?

    sort() changes the existing array and returns that same array. Declaring the array with const does not prevent this mutation; it only prevents assigning a different array to the variable.

    Copy the array before sorting when other code needs the original order:

    const ascending = […numbers].sort((a, b) => a – b);

    toSorted() provides the non-mutating alternative in modern JavaScript. It returns a new sorted array while leaving the source unchanged:

    const descending = numbers.toSorted((a, b) => b – a);

    Use sort() when changing the current array is intentional. Use toSorted(), or a spread copy followed by sort(), when immutability is required.

  • JavaScript data structures: choose by lookup, order, and uniqueness

    JavaScript data structures: choose by lookup, order, and uniqueness

    JavaScript data structures are easiest to choose when the required access pattern comes first. Use an array for indexed order, an object for simple string-keyed records, Map for flexible keyed lookup, and Set for uniqueness.

    These data structures in JavaScript also support stack and queue patterns. The best data structures JavaScript developers choose depend on whether code needs stable order, repeated values, fast membership checks, or removal from one end.

    When are arrays or objects the right choice?

    An array is an ordered, index-based collection. It allows duplicates and makes positional reads and updates straightforward, while searching for a value requires scanning. Use it for records displayed in sequence, batches, or data whose position matters.

    const colors = [“red”, “blue”, “red”]; The expression colors[1] returns “blue”, and colors.includes(“red”) checks for a value.

    A plain object is a record of properties identified by string or symbol keys. It suits fixed fields, configuration, and simple dictionaries. Numeric-looking keys are converted to strings, and inherited properties mean property checks should be deliberate.

    const user = { name: “Ari”, role: “editor” }; The expression user.role reads a known property directly.

    When should you use Map or Set instead of objects or arrays?

    Use Map when a collection is fundamentally a key-value lookup and keys may be any JavaScript value, including objects and functions. Map provides dedicated methods such as set, get, has, and delete, plus a size property.

    const prices = new Map([[“book”, 12]]); The expression prices.get(“book”) returns 12.

    Use Set when each value should occur only once. It provides membership checks and deletion by value, and it preserves insertion order during iteration, but it does not provide numeric indexes.

    const tags = new Set([“js”, “web”, “js”]); The set contains only “js” and “web”; tags.has(“web”) checks membership.

    Compare an object with Map by key rules, order, and operations. An object accepts string and symbol property keys and is record-oriented. Map accepts arbitrary key types, has collection-specific operations, and guarantees insertion-order iteration. Object enumeration follows property-key ordering rules, including special handling for integer-like keys, so the two structures are not interchangeable.

    Compare an array with Set by the same criteria. An array preserves duplicates, supports indexes, and can represent repeated events in sequence. Set enforces uniqueness and offers direct value membership, making it better for selected IDs, permissions, or visited nodes.

    How do stack and queue patterns work with arrays?

    A stack uses last-in, first-out access: the newest item is removed first. Arrays implement this pattern efficiently with push and pop.

    const stack = []; Then use stack.push(“draft”) to add an item and stack.pop() to remove the newest item.

    A queue uses first-in, first-out access: the oldest item is removed first. The simple array pattern adds with push and removes with shift.

    const queue = [“first”, “second”]; Use queue.push(“third”), then queue.shift() to remove “first”.

    Front removal with shift() can cost O(n) because remaining elements are reindexed. For a growing queue, keep a head index instead: const item = queue[head++]; This avoids repeatedly shifting every remaining element.

    How do JavaScript data structures compare by lookup, order, and uniqueness?

    • Keyed lookup: choose an object for simple string-keyed records, or Map for arbitrary key types and explicit map operations.
    • Order: choose an array for indexed positions, or Set when insertion order matters but duplicates must disappear.
    • Uniqueness: choose Set for automatic deduplication; arrays and objects require separate checks or transformation logic.
    • Removal pattern: use pop for a stack, shift for a small queue, or a head index for a queue with frequent front removals.
  • JavaScript Practice: Progressive Coding Challenges with Test Cases

    JavaScript Practice: Progressive Coding Challenges with Test Cases

    Build JavaScript practice through eight focused problems that increase in difficulty. Each exercise defines an input, required output, constraints, sample cases, and review criteria, so you can test behavior instead of relying on an open-ended project brief.

    Start with the first section, then move forward only when your implementation passes the listed edge cases. These JavaScript coding challenges are short enough for repeated attempts and code reviews.

    JavaScript Practice: Beginner String and Number Challenges

    Reverse a string

    Input: A string. Required output: The characters in reverse order. Constraints: Preserve every character, including spaces, and support empty input. Samples: "JavaScript" → "tpircSavaJ"; "" → "". Hint: Use a loop or reverse and join. Review: Check that no characters are lost and the source value is not mutated.

    Count vowels

    Input: A string. Required output: The number of a, e, i, o, and u characters. Constraints: Count case-insensitively and ignore nonletters. Samples: "JavaScript" → 3; "rhythm!" → 0. Hint: Normalize the string and use a vowel lookup. Review: Empty input must return 0, and uppercase vowels must count.

    Build FizzBuzz

    Input: A positive integer n. Required output: An array from 1 through n, replacing multiples of 3 with "Fizz", multiples of 5 with "Buzz", and multiples of both with "FizzBuzz". Constraints: 1 ≤ n ≤ 1,000. Samples: 5 → [1, 2, "Fizz", 4, "Buzz"]; 15 → [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]. Hint: Test divisibility by 15 first. Review: Preserve order and the number-versus-string value types.

    JavaScript Coding Challenges for Arrays and Objects

    Keep first occurrences

    Input: An integer array. Required output: A unique array preserving first-seen order. Constraints: Do not sort the values or change the source array. Samples: [3, 1, 3, 2, 1] → [3, 1, 2]; [] → []. Hint: Track seen values with a Set or lookup. Review: Test duplicates at the beginning, middle, and end, and verify the original array remains unchanged.

    Group records

    Input: An array of objects with name and team properties. Required output: An object mapping each team to an array of names. Constraints: Preserve input order and create no empty groups. Sample: [{name: "Ana", team: "red"}, {name: "Bo", team: "blue"}, {name: "Cy", team: "red"}] → {red: ["Ana", "Cy"], blue: ["Bo"]}. Hint: Build an accumulator as you iterate. Review: Check exact keys, name order, and behavior with an empty array.

    JavaScript Code Challenges for Functions and Data Transformation

    Compose unary functions

    Input: A list of synchronous unary functions and a value x. Required output: The result after applying functions from left to right. Constraints: Functions accept and return one value. Samples: [x=>x+2, x=>x*3], 4 → 18; [], 4 → 4. Hint: Reduce over the function list. Review: Confirm execution order and avoid mutating the list.

    Summarize a cart

    Input: An array of {price, qty} items and a tax rate. Required output: The total after tax, rounded to two decimals. Constraints: Prices, quantities, and tax are nonnegative; apply tax after calculating the subtotal. Samples: [{price: 10, qty: 2}], 0.1 → 22; [], 0.2 → 0. Hint: Reduce the subtotal before rounding. Review: Prevent string concatenation, handle zero items, and account for floating-point rounding.

    Async Extension: Reliable Fetch Behavior

    Retry an async request

    Input: A promise factory and a maximum-attempts integer. Required output: The first resolved value, or the final rejection after all attempts fail. Constraints: Call the factory once per attempt, require maxAttempts ≥ 1, and stop immediately after success. Samples: A factory yielding Error("E1"), Error("E2"), then "ok" with 3 attempts resolves to "ok" on call 3; two failures with maxAttempts=2 reject Error("E2"). Hint: Use an await loop with try/catch. Review: Preserve the final error and verify the exact attempt count.

  • JavaScript absolute value: How Math.abs() handles common inputs

    JavaScript absolute value: How Math.abs() handles common inputs

    JavaScript absolute value uses Math.abs() to return a number’s distance from zero. Negative values become positive, positive values stay unchanged, and zero remains zero. In other words, absolute value in JavaScript represents magnitude without a sign.

    The syntax is Math.abs(value). The function accepts one argument and applies JavaScript’s numeric conversion before calculating the result, so its behavior includes more than number literals.

    How does JavaScript absolute value work with Math.abs()?

    For ordinary numeric input, Math.abs() returns the input’s nonnegative magnitude. It does not change the original variable; use the returned value when the normalized number is needed.

    • Math.abs(-12) returns 12.
    • Math.abs(12) returns 12.
    • Math.abs(0) returns 0.
    • Math.abs(-3.75) returns 3.75.

    These results follow the mathematical definition: both -12 and 12 are 12 units from zero. The function removes the sign only when the value is negative; it does not round decimals or otherwise alter a finite number.

    What does absolute value in JavaScript return for strings and null?

    The JavaScript Math.abs function converts its argument to a number before applying absolute value. A string containing a valid numeric representation therefore produces a numeric result, while a string that cannot be converted produces NaN.

    • Math.abs(“-18”) returns 18.
    • Math.abs(“6.5”) returns 6.5.
    • Math.abs(” -9 “) returns 9; surrounding whitespace is ignored during conversion.
    • Math.abs(null) returns 0, because numeric conversion treats null as zero.
    • Math.abs(“18px”) returns NaN, because the complete string is not a valid number.
    • Math.abs(“hello”) returns NaN.

    An empty string also converts to zero, so Math.abs(“”) returns 0. By contrast, Math.abs(undefined) returns NaN. NaN signals that the conversion did not produce a usable numeric result; it is not a positive or negative number.

    How can Math.abs(a – b) find the distance between two numbers?

    Use Math.abs(a – b) to calculate the absolute difference between two numbers. Subtraction happens first, and Math.abs() then removes the direction of that difference. This makes the result the same regardless of which number is larger.

    For example, Math.abs(18 – 25) returns 7. Reversing the operands, as in Math.abs(25 – 18), also returns 7. The same pattern works with variables:

    const distance = Math.abs(currentValue – targetValue);

    If currentValue is 42 and targetValue is 50, distance is 8. This pattern is useful for comparing measurements, positions, scores, or other numeric values where only the size of the difference matters.

    How does JavaScript Math.abs handle NaN, Infinity, and -0?

    Special numeric values follow predictable rules:

    • Math.abs(NaN) returns NaN. An unknown numeric result remains unknown.
    • Math.abs(Infinity) returns Infinity.
    • Math.abs(-Infinity) returns Infinity.
    • Math.abs(-0) returns positive zero, displayed as 0.

    JavaScript distinguishes positive and negative zero internally even though both usually display as 0. After Math.abs(-0), the sign is positive. The function also returns NaN when called without an argument: Math.abs() has no value to convert.

  • Check If String Is Empty in JavaScript

    Check If String Is Empty in JavaScript

    Use strict equality to check if string is empty when the input is already known to be a string: value === ”. To check if a string is empty in a validation rule, choose a different test when spaces should count as no content or when the value may be missing.

    The practical answer to how to check if a string is empty depends on the definition of “empty”: an exact zero-character value, whitespace-only text, or an absent value.

    Check if string is empty: value === ” or value.length === 0

    For a value guaranteed to be a primitive string, these two checks identify an exact empty string:

    • value === ” compares the value directly with JavaScript’s empty string literal. It does not coerce numbers, booleans, or other values.
    • value.length === 0 checks whether the string contains zero characters. It produces the same result for a known string.

    Strict equality is usually the clearest option because it states the intended value directly. The length form is useful when you are already working with string properties or want to emphasize the character count.

    Neither check treats a string containing spaces as empty. For example, ‘ ‘ === ” is false, and the string’s length is greater than zero.

    Treat whitespace-only text as empty with value.trim().length === 0

    Use value.trim().length === 0 when leading and trailing whitespace should not count as content. The trim() method removes whitespace from both ends of a string, so this condition matches all of these examples:

    • ”
    • ‘ ‘
    • ‘ ’
    • ‘ text ‘ does not match because text remains after trimming

    trim() returns a new string and does not modify the original value. Use the exact equality or length check instead when spaces are meaningful, such as in a fixed-format value where padding must be preserved.

    For checking an empty string in JavaScript when the input type is not guaranteed, combine trimming with a type guard:

    typeof value === ‘string’ && value.trim().length === 0

    This prevents trim() from being called on a number, object, or other non-string value.

    Handle null or undefined before checking

    null and undefined are missing-value states, not empty strings. They require a separate decision. Accessing value.length or calling value.trim() on either value throws a TypeError, so guard them before using string methods.

    An explicit null or undefined guard is:

    value === null || value === undefined

    For an optional field where missing values should be rejected separately from empty text, use conditions such as:

    • value === null || value === undefined for a missing value
    • typeof value === ‘string’ && value.length === 0 for an exact empty string
    • typeof value === ‘string’ && value.trim().length === 0 for empty or whitespace-only text

    If your rule defines both missing and blank as invalid, combine those cases explicitly:

    value === null || value === undefined || (typeof value === ‘string’ && value.trim().length === 0)

    This condition does not silently classify unrelated types as empty. The shorter expression value == null also matches only null and undefined, but the explicit form makes that intent easier to read.

    Avoid truthiness surprises with !value and optional values

    !value tests whether a value is falsy, not whether it is an empty string. It evaluates to true for an empty string, but also for:

    • 0
    • false
    • null
    • undefined
    • NaN

    It also does not identify whitespace-only text: !’ ‘ is false because a non-empty string is truthy. Use !value only when every falsy value should be treated as invalid. If zero or false are valid inputs, use a strict string, trimming, or null check that matches the required definition of empty.

  • JavaScript object methods explained: this, ownership, and prototypes

    JavaScript object methods explained: this, ownership, and prototypes

    JavaScript object methods are functions stored as object properties. The call site determines the value of this, while the method’s location determines whether it is an own property or inherited through a prototype.

    The same ideas apply to object literals, instances created by classes, and built-in APIs such as Object.keys. A small set of concrete examples makes the differences clear.

    JavaScript object methods: function properties, shorthand syntax, and calls

    A function becomes an object method when it is assigned to a property and invoked through that object. The traditional function-property syntax looks like this:

    const user = { name: “Mina”, greet: function () { return “Hi, ” + this.name; } };

    Calling user.greet() executes the function with user as its receiver. The method shorthand provides the same behavior with less syntax:

    const user = { name: “Mina”, greet() { return “Hi, ” + this.name; } };

    Here, user.greet() returns “Hi, Mina”. Shorthand is not a special kind of function. It is concise syntax for defining a regular method in an object literal. The important detail is the property access followed by parentheses: user.greet().

    How this gets its value from the call-site receiver

    For regular object methods, this usually comes from the object before the dot. In user.greet(), the receiver is user. Calling the same function through another object changes the receiver:

    const colleague = { name: “Ravi” }; user.greet.call(colleague);

    This call returns “Hi, Ravi”. The function has not changed; only its receiver has.

    Detaching the function removes that receiver:

    const speak = user.greet; speak();

    In strict-mode code, including JavaScript modules and class methods, this is undefined in the detached call. The method therefore cannot read this.name. Use user.greet() when the receiver should remain attached, or create a bound function with const speak = user.greet.bind(user).

    An arrow function does not acquire its own receiver from a method call. Its this is lexical, inherited from the surrounding scope. Therefore, greet: () => this.name is not a replacement for a regular receiver-based method when the function needs the object that appears before the dot.

    Object methods: own properties versus instance and class prototype methods

    Methods defined directly in an object literal are own properties. The function belongs to that particular object:

    const literalUser = { name: “Mina”, greet() { return “Hi, ” + this.name; } };

    A class uses a different ownership model:

    class User { constructor(name) { this.name = name; } greet() { return “Hi, ” + this.name; } } const mina = new User(“Mina”);

    mina.name is an own property because the constructor creates it on the instance. mina.greet works, but the function is stored on User.prototype, not copied onto mina. JavaScript looks along the prototype chain when it does not find a property directly on the instance.

    Object.hasOwn(mina, “name”) returns true, while Object.hasOwn(mina, “greet”) returns false. Prototype sharing lets every User instance use one method function. Assigning a function inside the constructor would instead create a separate own method for every instance.

    JS object methods and useful static Object methods

    Some object methods are static methods on the built-in Object constructor. They are called as Object.method(), not as methods of the data object. For example:

    Object.keys(user) returns an array of the object’s enumerable own property names, such as [“name”, “greet”]. Related static methods include Object.values(user) for values and Object.entries(user) for key-value pairs.

    Object.hasOwn(user, “name”) checks own-property ownership without searching the prototype chain. Object.assign(target, source) copies enumerable properties into a target object, while Object.create(prototype) creates an object with a chosen prototype.

    These static APIs differ from instance or prototype methods such as user.greet() and user.toString(). The first group is called on Object; the second is reached through a specific object and may use that object as the receiver.

  • JavaScript Calendar: Build a Month Grid with Events

    JavaScript Calendar: Build a Month Grid with Events

    Build a JavaScript calendar that renders a navigable month grid and marks events from structured data with native JavaScript. Keep month state separate from event data so each navigation click can rerender the grid without losing the current view.

    Keep the calendar JavaScript in one module: the same render function can serve the initial load and every previous or next month action.

    Set up the JavaScript calendar HTML and event data

    Give the interface three hooks: a month label, previous and next buttons, and an empty grid. For example, use data-calendar-label, data-calendar-previous, data-calendar-next, and data-calendar-grid attributes. Query them with document.querySelector so the widget does not depend on a particular framework.

    Store events with normalized local date keys. The date uses a four-digit year, two-digit month, and two-digit day:

    const events = [{ date: ‘2025-01-08’, title: ‘Planning review’ }, { date: ‘2025-01-21’, title: ‘Release’ }];

    Build an index once, outside the renderer, so multiple events can share a date:

    const eventsByDate = events.reduce((map, event) => { const list = map.get(event.date) || []; list.push(event); map.set(event.date, list); return map; }, new Map());

    Use a state object such as const state = { year: 2025, month: 0 }; JavaScript months are zero-based: 0 means January and 11 means December. The displayed month number is therefore the internal month plus one.

    Calculate first weekdays, month lengths, and grid cells

    Calculate the first weekday and number of days whenever the month is rendered:

    const firstWeekday = new Date(state.year, state.month, 1).getDay();
    const daysInMonth = new Date(state.year, state.month + 1, 0).getDate();

    getDay() returns Sunday as 0 and Saturday as 6. The second expression uses day 0 of the following month, which returns the final day of the selected month. This avoids hard-coded month lengths and handles leap years.

    Reserve enough cells for the leading blank cells before day 1 and the trailing cells after the final day:

    const cellCount = Math.ceil((firstWeekday + daysInMonth) / 7) * 7;

    For cell index i, calculate the visible day with const day = i – firstWeekday + 1;. Values below 1 are leading cells; values above daysInMonth are trailing cells. Render those positions as empty, noninteractive cells rather than inventing dates.

    Render a JavaScript calendar widget with event markers

    Clear the grid at the start of every render, then loop from 0 to cellCount – 1. For each valid day, create a button or cell and generate a stable key:

    const toKey = (year, month, day) => `${year}-${String(month + 1).padStart(2, ‘0’)}-${String(day).padStart(2, ‘0’)}`;

    For each valid day, create a button, set button.dataset.date = key, and set its visible text to the day number. Retrieve matching events with const dayEvents = eventsByDate.get(key) || []; Then add an event marker when the array is not empty, such as a bullet or count. Use the event titles for the button’s accessible label or title, for example, dayEvents.map(event => event.title).join(‘, ‘).

    This stable date key lets click handlers identify a day without parsing its displayed number. It also keeps events attached correctly when the month changes. A JavaScript calendar widget can use the same structure for birthdays, appointments, or release dates.

    Add previous and next controls to a JavaScript event calendar

    Attach click handlers that update the zero-based month and then call render():

    previous.addEventListener(‘click’, () => { if (state.month === 0) { state.month = 11; state.year–; } else state.month–; render(); });

    next.addEventListener(‘click’, () => { if (state.month === 11) { state.month = 0; state.year++; } else state.month++; render(); });

    Update the label inside render() with new Intl.DateTimeFormat(‘en’, { month: ‘long’, year: ‘numeric’ }).format(new Date(state.year, state.month, 1)). Keep the state object and event index outside the renderer. Reinitializing either one inside render() would reset navigation or discard event data. Call render() once after wiring the controls to display the initial month.

  • JavaScript replaceAll: How to Replace Every Match

    JavaScript replaceAll: How to Replace Every Match

    JavaScript replaceAll replaces every occurrence of matching text and returns a new string. It does not modify the original string, so you must store or use the returned value.

    Use replaceAll in JavaScript with a literal string when the text is known, or with a global regular expression when matching needs flags or pattern logic.

    How JavaScript replaceAll Replaces Every Literal Match

    Pass a string as the first argument to search for literal text. Regular-expression characters in that argument, such as + or ., have no special meaning.

    Example: const source = “red, red, blue”;

    const updated = source.replaceAll(“red”, “green”);

    console.log(updated); // “green, green, blue”

    console.log(source); // “red, red, blue”

    The returned value contains every replacement, while source remains unchanged. Literal matching is case-sensitive, so searching for “red” does not replace “Red”. A replacement can be a fixed string or a function that calculates the result for each match.

    How Does JS replaceAll Differ from replace?

    JS replaceAll replaces every literal match by default. The replace() method replaces only the first literal match when its search value is a string.

    Example: const source = “red, red, blue”;

    source.replace(“red”, “green”); // “green, red, blue”

    source.replaceAll(“red”, “green”); // “green, green, blue”

    With a regular expression, replace() replaces every match only when the expression has the global g flag:

    source.replace(/red/g, “green”); // “green, green, blue”

    Use replaceAll() for clear literal replacement. Use replace() when you intentionally need only the first match, or when existing code already handles a regular-expression pattern.

    How to Use replaceAll() in JavaScript with a Global Regex

    A regular expression passed to replaceAll() must be global. The expression must include the g flag, or JavaScript throws a TypeError instead of performing a partial replacement.

    Example: const text = “Red red RED”;

    const result = text.replaceAll(/red/gi, “blue”);

    // “blue blue blue”

    The i flag makes the pattern case-insensitive, while g makes it apply to every match. A non-global expression such as /red/i is not valid for replaceAll().

    For dynamic text that should be treated literally, pass the value directly as a string:

    const term = “red+blue”;

    text.replaceAll(term, “color”);

    If a dynamic value must be included in a larger regular expression, escape its pattern characters before constructing the expression:

    function escapeRegExp(value) {

    return value.replace(/[.*+?^${}()|[\]\\]/g, “\\$&”);

    }

    const pattern = new RegExp(escapeRegExp(term), “g”);

    text.replaceAll(pattern, “color”);

    This keeps characters from the user-provided value from changing the regex’s meaning and preserves the required global behavior.

    How Do Callbacks and Special Replacement Tokens Work?

    Pass a function as the replacement to calculate a different result for each match. The callback receives the complete match first, followed by captured groups and other match details.

    Example: const prices = “Item: $5, Item: $12”;

    const raised = prices.replaceAll(/\$(\d+)/g, (match, amount) => “$” + (Number(amount) + 1));

    // “Item: $6, Item: $13”

    When the replacement is a string, JavaScript recognizes special replacement tokens. $& inserts the complete match, $1 inserts the first captured group, $2 inserts the second, $` inserts the text before the match, $’ inserts the text after the match, and $$ inserts a literal dollar sign.

    Example: const marked = “red blue”.replaceAll(/(\w+)/g, “[$&]”);

    // “[red] [blue]”

    These tokens are interpreted when the replacement is a string, including when the search value is a literal string. A callback’s returned value is inserted as-is, so dollar signs returned by the function are not treated as replacement tokens.

  • Get Object Keys in JavaScript: Find, Read, and Iterate

    Get Object Keys in JavaScript: Find, Read, and Iterate

    To get object keys in JavaScript, use JavaScript Object.keys() to list an object’s own enumerable string keys. Use bracket notation to read a property whose name is stored in a variable, and use Object.entries() to process keys and values together.

    Finding a key and accessing a property are separate operations. Object.keys() discovers available names; bracket access retrieves a value after you choose a name. The methods below focus on own properties, so inherited data does not silently enter your results.

    Get object keys in JavaScript with Object.keys()

    Object.keys(source) returns a new array containing the object’s own enumerable property names that are strings. It excludes inherited properties, non-enumerable properties, and symbols. The result is shallow: it lists keys on the source object, not keys inside nested objects.

    • const profile = { name: “Mina”, role: “editor” };
    • Object.keys(profile) returns [“name”, “role”].

    The returned array is useful for displaying field names, checking whether an object has any enumerable data, or building a controlled iteration. An object with no own enumerable string properties produces an empty array.

    Get a key from an object in JavaScript, then read its value

    When you already know a key, do not search the key array to read its value. Dot notation works for a known identifier-like property name, such as profile.name. Bracket notation evaluates an expression, making it the required form for dynamic names, such as profile[field]. It also handles names that are not valid identifiers, including “display-name”.

    const field = “role”; const value = profile[field]; stores “editor” in value. In contrast, profile.field looks for a property literally named field; it does not use the variable’s contents. Reading a missing property returns undefined, whether the missing name is supplied with dot or bracket notation.

    Use JavaScript Object.keys(), Object.values(), and Object.entries()

    JavaScript Object.keys, Object.values(), and Object.entries() use the same selection rule: they include an object’s own enumerable string-keyed properties. They differ in what each returns:

    • Object.keys(profile) returns an array of property names.
    • Object.values(profile) returns the corresponding values, without their names.
    • Object.entries(profile) returns pairs such as [“name”, “Mina”].

    Use Object.values() when only the data matters. Use Object.entries() when each operation needs both the property name and its value:

    for (const [key, value] of Object.entries(profile)) { console.log(key, value); }

    This pattern avoids a second lookup and works naturally with destructuring. It iterates only own enumerable string keys, matching the behavior of Object.keys().

    Check own, symbol, and inherited keys with hasOwn and Reflect.ownKeys()

    Object.hasOwn(object, key) checks whether a property belongs directly to the object. It returns true for an own property even when that property is non-enumerable, and false for an inherited property. It is safer and clearer than calling a possibly overridden object.hasOwnProperty() method.

    • const parent = { inherited: true };
    • const record = Object.create(parent); record.visible = true;
    • Object.hasOwn(record, “visible”) returns true.
    • Object.hasOwn(record, “inherited”) returns false.

    Reflect.ownKeys(record) returns every own property key, including enumerable and non-enumerable string keys plus symbol keys. This is broader than Object.keys(), Object.values(), and Object.entries(), which omit symbols and non-enumerable properties. Use Object.getOwnPropertyNames() for all own string keys, or Object.getOwnPropertySymbols() for own symbol keys.

    A for…in loop is different: it visits enumerable string keys from the object and its prototype chain. If you use one, guard each key with Object.hasOwn(record, key). For own enumerable data, Object.keys() or Object.entries() is usually clearer.