Free sample · answers included

Free Salesforce JavaScript Developer
Practice Questions

18 free JavaScript Developer practice questions from our bank of 300 reviewed questions, picked across all 7 official exam sections in proportion to their weight. Each one shows the correct answer, why it is right and why the others are wrong, and the official documentation it was checked against.

Last updated

What is the JavaScript Developer exam like?

60+5

Scored + unscored questions

105 min

Time limit

65%

Passing score

$200

Registration (retake $100)

Confirm current details in the official JavaScript Developer exam guide.

Questions by exam section

Heavier sections get more questions, the same way the real exam and our 60-question practice exams are weighted.

Variables, Types, and Collections

23% of the exam
  1. Question 1 · Harder

    Ursa Major Solar receives panel quantities as strings, and a developer converts them with a one-line map() call. Refer to the code below:
    const quantities = ['10', '10', '10'].map(parseInt);
    console.log(quantities);
    What is logged to the console?
    • A.[ 10, 10, 10 ]
    • B.[ 10, NaN, 2 ]
    • C.[ 10, NaN, NaN ]
    • D.[ '10', '10', '10' ]
    Show the answer and explanation
    Correct answer: B. [ 10, NaN, 2 ]
    map() calls its callback with three arguments (the element, its index, and the array), so each call is really parseInt('10', index). Index 0 means the radix is treated as unspecified, giving 10; radix 1 is invalid, giving NaN; and radix 2 parses '10' as binary, giving 2. [ 10, 10, 10 ] is what map(Number) or map(s => parseInt(s, 10)) would produce. The all-string result assumes map() returns the original values, and [ 10, NaN, NaN ] misses that '10' is a valid binary number.
  2. Question 2 · Harder

    Users of a Cumulus Financial app in California report that due dates display one day early. The due date arrives from the API as a date-only string. Refer to the code below:
    const dueDate = new Date('2025-07-04');
    console.log(dueDate.getDate());
    The code logs 3 for these users. What is the cause?
    • A.Date-only ISO 8601 strings are parsed as UTC midnight, and getDate() returns the day in the user's local time zone, which is still July 3 in California.
    • B.getDate() returns a zero-based day of the month, so the value 3 represents the fourth day.
    • C.Date-only strings are parsed in local time, but getDate() always returns the day in UTC.
    • D.getDate() returns the day of the week rather than the day of the month.
    Show the answer and explanation
    Correct answer: A. Date-only ISO 8601 strings are parsed as UTC midnight, and getDate() returns the day in the user's local time zone, which is still July 3 in California.
    Under the ECMAScript date time string format, a date-only string such as '2025-07-04' is interpreted as UTC, while a date-time string without an offset is interpreted as local time. UTC midnight on July 4 is 5 PM on July 3 in California, and getDate() reports the local day, so it returns 3. getDate() is one-based (1-31), so the zero-based explanation is wrong, and it returns the day of the month; the day of the week comes from getDay(). The explanation that parsing is local and the getter is UTC reverses the actual behavior. Constructing the date with new Date(2025, 6, 4) or '2025-07-04T00:00:00' avoids the shift.
  3. Question 3 · Harder · Choose 3

    A Universal Containers developer serializes a case payload before sending it to an external system. Refer to the code below:
    const payload = {
        id: 42,
        note: undefined,
        closedAt: null,
        format() {
            return 'x';
        },
        tags: ['vip', undefined],
        created: new Date(0)
    };
    const json = JSON.stringify(payload);
    Which three statements about the value of json are true? Choose 3 answers.
    • A.tags is serialized as ["vip"].
    • B.The note property does not appear in the string.
    • C.created is serialized as the number 0.
    • D.closedAt is serialized as null.
    • E.The format property does not appear in the string.
    Show the answer and explanation
    Correct answers: B. The note property does not appear in the string.; D. closedAt is serialized as null.; E. The format property does not appear in the string.
    JSON.stringify() omits object properties whose values are undefined or functions, so neither note nor format appears in the output. null is a valid JSON value, so closedAt is kept as null. Inside arrays, undefined is not dropped but converted to null, so tags becomes ["vip",null] rather than ["vip"]. Date objects are serialized through their toJSON() method, which returns an ISO 8601 string ("1970-01-01T00:00:00.000Z"), not a number.
  4. Question 4 · Medium · Choose 2

    A developer at Ursa Major Solar writes code to choose a tax rate, but the script fails before any line runs. Refer to the code below:
    const region = 'EU';
    const taxRate;
    if (region === 'EU') {
        taxRate = 0.2;
    } else {
        taxRate = 0.08;
    }
    console.log(taxRate);
    Which two changes allow the code to log the correct tax rate? Choose 2 answers.
    • A.Replace line 2 with const taxRate = null; and keep the if...else assignments.
    • B.Replace line 2 with let taxRate; and keep the if...else assignments.
    • C.Remove line 2 and declare const taxRate; inside each branch of the if...else statement.
    • D.Replace lines 2 through 7 with const taxRate = region === 'EU' ? 0.2 : 0.08;
    • E.Add 'use strict'; as the first line of the script.
    Show the answer and explanation
    Correct answers: B. Replace line 2 with let taxRate; and keep the if...else assignments.; D. Replace lines 2 through 7 with const taxRate = region === 'EU' ? 0.2 : 0.08;
    A const declaration must be initialized in the same statement, so const taxRate; raises SyntaxError: Missing initializer in const declaration and the script never runs. Declaring with let allows the variable to be created without a value and assigned later in either branch, and a conditional (ternary) expression lets const be initialized with the correct value in a single statement. Initializing the constant to null removes the syntax error, but the later assignments throw TypeError: Assignment to constant variable. Declaring const taxRate; inside each branch still lacks an initializer, and even with one the block-scoped variable would not be visible to console.log. Strict mode does not change the rule that const requires an initializer.

Objects, Functions, and Classes

25% of the exam
  1. Question 5 · Medium · Choose 3

    A developer at Universal Containers loads a dashboard with <script type="module" src="dashboard.js"></script> instead of a classic script tag. Which three statements are true about how the browser handles dashboard.js? Choose 3 answers.
    • A.The script is deferred automatically, so it runs after the HTML document has been parsed even without a defer attribute.
    • B.Top-level this in dashboard.js refers to the window object.
    • C.The code runs in strict mode even without a 'use strict' directive.
    • D.The page works when it is opened directly from the local file system with a file:// URL.
    • E.A var declared at the top level of dashboard.js is scoped to the module and does not become a property of window.
    Show the answer and explanation
    Correct answers: A. The script is deferred automatically, so it runs after the HTML document has been parsed even without a defer attribute.; C. The code runs in strict mode even without a 'use strict' directive.; E. A var declared at the top level of dashboard.js is scoped to the module and does not become a property of window.
    Module scripts are deferred by default, so they execute after the document is parsed, and module code always runs in strict mode. Top-level declarations in a module, including var, are scoped to that module rather than attached to the global object, so other scripts cannot read them unless the module exports them or assigns them to window explicitly. Top-level this in a module is undefined, not window. Browsers apply CORS rules to module scripts, so opening the page from a file:// URL fails and a local web server is needed for testing.
  2. Question 6 · Easier

    A Universal Containers integration builds an update payload whose key comes from a variable.
    const field = 'status';
    const value = 'Closed';
    const update = { [field]: value, field };
    console.log(update);
    What is logged to the console?
    • A.{ field: 'Closed', status: 'status' }
    • B.{ status: 'Closed', field: 'status' }
    • C.{ status: 'Closed' }
    • D.A SyntaxError, because object keys cannot come from variables
    Show the answer and explanation
    Correct answer: B. { status: 'Closed', field: 'status' }
    Square brackets in an object literal create a computed property name, so [field] evaluates the variable and uses its value, 'status', as the key. The shorthand field is equivalent to field: field, which adds a property named field whose value is the string 'status'. The option with field: 'Closed' reverses the two features, { status: 'Closed' } ignores the shorthand property, and both syntaxes have been valid since ES2015, so no SyntaxError is thrown.
  3. Question 7 · Harder

    Cumulus Financial requires that an account balance can be changed only through the deposit method. A developer uses a private class field and then tests it.
    class Wallet {
        #balance = 0;
        deposit(amount) {
            this.#balance += amount;
            return this.#balance;
        }
    }
    const wallet = new Wallet();
    console.log(wallet.deposit(50));
    console.log(wallet.#balance);
    What is the result of running this script?
    • A.50 is logged, and then undefined is logged.
    • B.50 is logged twice.
    • C.50 is logged, and then a TypeError is thrown.
    • D.A SyntaxError is reported, and nothing is logged.
    Show the answer and explanation
    Correct answer: D. A SyntaxError is reported, and nothing is logged.
    Referencing a private name such as #balance outside the class body that declares it is an early error, so the script fails to parse and a SyntaxError is reported before any line runs. Because parsing fails, even the valid deposit call never executes and nothing is logged. Private fields are not ordinary properties that evaluate to undefined or expose their value outside the class, and the error is not a runtime TypeError raised after the first log.
  4. Question 8 · Medium · Choose 2

    The development lead at AW Computing is reviewing a pull request that converts every function in a legacy library to an arrow function. Which two behaviors of arrow functions should the lead consider before approving the change? Choose 2 answers.
    • A.Arrow functions are hoisted together with their body, so they can be called before their definition.
    • B.Arrow functions cannot be called with new, so any function used as a constructor must stay a regular function.
    • C.Arrow functions receive this from the object that calls them, just like regular methods.
    • D.Arrow functions do not support default parameter values.
    • E.Arrow functions do not have their own arguments object, so code that reads arguments must switch to rest parameters.
    Show the answer and explanation
    Correct answers: B. Arrow functions cannot be called with new, so any function used as a constructor must stay a regular function.; E. Arrow functions do not have their own arguments object, so code that reads arguments must switch to rest parameters.
    Arrow functions cannot be used as constructors, so calling one with new throws a TypeError, and they do not have their own arguments object, so rest parameters are the replacement. Arrow functions are expressions assigned to variables, so they are not hoisted with their body the way function declarations are. They take this lexically from the surrounding scope rather than from the caller, which is the opposite of how regular methods behave. Default parameters work the same in arrow functions as in regular functions.
  5. Question 9 · Harder

    A developer at AW Computing writes a function factory for pricing adjustments:
    function makeMultiplier(factor) {
        return function (value) {
            factor = factor + 1;
            return value * factor;
        };
    }
    const scale = makeMultiplier(2);
    const scaleAgain = makeMultiplier(2);
    console.log(scale(10), scale(10), scaleAgain(10));
    What is logged to the console?
    • A.20 20 20
    • B.30 30 30
    • C.30 40 30
    • D.30 40 50
    Show the answer and explanation
    Correct answer: C. 30 40 30
    The parameter factor is a variable in makeMultiplier's scope, and the returned closure can both read and reassign it. Each call to scale increments the same factor, so the first call computes 10 * 3 = 30 and the second computes 10 * 4 = 40. scaleAgain comes from a separate call to makeMultiplier, so it has its own factor starting at 2 and returns 30. 20 20 20 ignores the increment, 30 30 30 assumes factor resets on each call, and 30 40 50 assumes both closures share one factor variable.

Browser and Events

17% of the exam
  1. Question 10 · Harder

    Refer to the HTML and code below, which Get Cloudy Consulting uses on an approval screen:
    <div id="panel">
        <button id="approve">Approve</button>
    </div>
    const panel = document.querySelector('#panel');
    const btn = document.querySelector('#approve');
    panel.addEventListener('click', () => console.log('panel'));
    btn.addEventListener('click', (event) => {
        console.log('first');
        event.stopImmediatePropagation();
    });
    btn.addEventListener('click', () => console.log('second'));
    What is logged when the Approve button is clicked?
    • A.first
    • B.first, second
    • C.first, second, panel
    • D.first, panel
    Show the answer and explanation
    Correct answer: A. first
    stopImmediatePropagation() prevents any remaining listeners from being called, both the other listeners on the same element and those on ancestors, so only first is logged. first, second is what stopPropagation() would produce, because that method lets the remaining listeners on the current element run but blocks ancestors. first, second, panel ignores the call entirely. first, panel reverses the behavior by skipping the sibling listener while still bubbling to the ancestor.
  2. Question 11 · Harder

    Refer to the HTML and code below from a Northern Trail Outfitters task page:
    <ul id="tasks">
        <li class="item">Call</li>
        <li class="item">Email</li>
    </ul>
    const list = document.querySelector('#tasks');
    const live = list.getElementsByClassName('item');
    const snapshot = list.querySelectorAll('.item');
    const li = document.createElement('li');
    li.className = 'item';
    list.appendChild(li);
    console.log(live.length, snapshot.length);
    What is logged to the console?
    • A.2 2
    • B.3 3
    • C.3 2
    • D.2 3
    Show the answer and explanation
    Correct answer: C. 3 2
    getElementsByClassName() returns a live HTMLCollection that always reflects the current DOM, so the appended item appears in it immediately and it reports 3. querySelectorAll() returns a static NodeList, a snapshot taken when it was called, so it still reports 2. 2 2 and 3 3 treat both collections as the same kind, and 2 3 reverses which one is live.
  3. Question 12 · Medium · Choose 2

    Cumulus Financial's single-page account app switches between tabs without reloading the page. Refer to the code below:
    function showTab(tab) {
        renderTab(tab);
        history.pushState({ tab: tab }, '', `/account/${tab}`);
    }
    
    window.addEventListener('popstate', (event) => {
        renderTab(event.state ? event.state.tab : 'summary');
    });
    Which two statements about this code are true? Choose 2 answers.
    • A.Calling showTab('billing') changes the address bar to /account/billing without the browser loading that URL.
    • B.Calling showTab('billing') immediately fires a popstate event, so renderTab() runs twice.
    • C.When the user clicks the browser's Back button, the popstate listener runs and event.state holds the state of the history entry being returned to, or null for an entry created without pushState().
    • D.pushState() can set the URL to a different origin, such as https://partner.example.com/account.
    • E.The third argument to pushState() must be an absolute URL, so the relative path /account/billing throws an error.
    Show the answer and explanation
    Correct answers: A. Calling showTab('billing') changes the address bar to /account/billing without the browser loading that URL.; C. When the user clicks the browser's Back button, the popstate listener runs and event.state holds the state of the history entry being returned to, or null for an entry created without pushState().
    pushState() adds a history entry and updates the URL, and the browser does not attempt to load that URL, which is why single-page apps use it for client-side routing. Calling pushState() does not trigger popstate; the event fires when the user navigates the session history, for example with the Back or Forward button, and event.state carries a copy of that entry's state object. The new URL must have the same origin as the current page, otherwise pushState() throws an exception. A relative URL is allowed and is resolved against the current URL, so /account/billing works.

Debugging and Error Handling

7% of the exam
  1. Question 13 · Medium · Choose 2

    Universal Containers receives cart data from a partner API as a string. Testing found two failure cases: the partner sometimes sends a truncated payload such as {"cart": {"items": [ and sometimes sends {}.
    function countItems(payload) {
        try {
            const data = JSON.parse(payload);
            return data.cart.items.length;
        } catch (err) {
            console.log(err.name);
            return 0;
        }
    }
    Which two values does the catch block log for these two failure cases? Choose 2 answers.
    • A.SyntaxError
    • B.ReferenceError
    • C.RangeError
    • D.TypeError
    • E.JSONError
    Show the answer and explanation
    Correct answers: A. SyntaxError; D. TypeError
    JSON.parse() throws a SyntaxError when the string is not valid JSON, which is what happens with the truncated payload. With {}, parsing succeeds and returns an empty object, so data.cart is undefined and reading items from undefined throws a TypeError. A ReferenceError is thrown when code refers to an undeclared identifier, but every identifier in the function is declared. A RangeError signals a numeric value outside its allowed range, which neither payload produces. There is no built-in JSONError type; JSON parse failures are reported as SyntaxError.

Asynchronous Programming

13% of the exam
  1. Question 14 · Easier

    Northern Trail Outfitters is building a trail dashboard that calls three independent APIs: weather, trail conditions, and permits. Each API call returns a Promise. The dashboard must wait until every request has finished, render each widget whose request succeeded, and show an error message only in the widgets whose request failed. Which method should the developer use to combine the three promises?
    • A.Promise.all()
    • B.Promise.race()
    • C.Promise.allSettled()
    • D.Promise.any()
    Show the answer and explanation
    Correct answer: C. Promise.allSettled()
    Promise.allSettled() waits for every input promise to settle and fulfills with an array of outcome objects, each with status: 'fulfilled' and a value or status: 'rejected' and a reason, so the dashboard can render successes and failures individually. Promise.all() rejects as soon as one request fails, so the results of the successful requests are not available in its rejection. Promise.race() settles with whichever request settles first, so the other two outcomes are lost. Promise.any() fulfills with only the first successful result and rejects with an AggregateError only when all three fail.
  2. Question 15 · Medium · Choose 3

    Northern Trail Outfitters logs the name of each trail when a timer fires. The developer declared the counter with let, expecting each callback to capture its own value. Refer to the code below:
    const trails = ['Ridge', 'Lake', 'Pine'];
    let i = 0;
    while (i < trails.length) {
        setTimeout(() => console.log(trails[i]), 100);
        i++;
    }
    The code logs undefined three times instead of Ridge, Lake, and Pine. Which three changes make the code log the three trail names? Choose 3 answers.
    • A.Change let i = 0; to var i = 0;.
    • B.Replace the while loop with for (const trail of trails) { setTimeout(() => console.log(trail), 100); }.
    • C.Add const index = i; as the first statement in the loop body and change the callback to () => console.log(trails[index]).
    • D.Change the delay from 100 to i * 100 so that each callback runs at a different time.
    • E.Replace the while loop with trails.forEach((trail) => setTimeout(() => console.log(trail), 100));.
    Show the answer and explanation
    Correct answers: B. Replace the while loop with for (const trail of trails) { setTimeout(() => console.log(trail), 100); }.; C. Add const index = i; as the first statement in the loop body and change the callback to () => console.log(trails[index]).; E. Replace the while loop with trails.forEach((trail) => setTimeout(() => console.log(trail), 100));.
    let creates a new binding for each iteration only when it is declared in a for loop header; here i is declared once outside the loop, so all three callbacks close over the same variable, which is 3 by the time the timers fire after the loop has finished, and trails[3] is undefined. A for...of loop with a const variable, a const copy declared inside the loop body, and the parameter of a forEach() callback each give every callback its own binding that holds the current trail or index. Switching to var keeps a single shared, function-scoped variable. Staggering the delays changes only when each callback runs, not which variable it reads, so every callback still reads 3.

Server Side JavaScript

8% of the exam
  1. Question 16 · Medium · Choose 2

    Ursa Major Solar's inventory service uses an EventEmitter from the core events module to notify other modules when stock levels change. A new developer asks how the emitter behaves. Which two statements are true? Choose 2 answers.
    • A.emit() returns a Promise that resolves after every listener has finished.
    • B.Adding more than 10 listeners for the same event makes the emitter remove the oldest listeners automatically.
    • C.When emit() is called, the listeners run synchronously in the order in which they were registered.
    • D.A listener registered with on() is removed automatically after the event fires once.
    • E.Emitting an 'error' event when no 'error' listener is registered throws the error, and the process exits if nothing catches it.
    Show the answer and explanation
    Correct answers: C. When emit() is called, the listeners run synchronously in the order in which they were registered.; E. Emitting an 'error' event when no 'error' listener is registered throws the error, and the process exits if nothing catches it.
    The events docs state that an EventEmitter calls all listeners synchronously in registration order, and that emitting 'error' without at least one 'error' listener throws the error, prints a stack trace and exits the process, which is why services should always register an 'error' handler. emit() returns a boolean (true if the event had listeners, false otherwise), not a Promise. Exceeding the default of 10 listeners only prints a possible memory-leak warning; no listener is removed. Automatic removal after one call is the behaviour of once(), while listeners added with on() stay registered until they are removed.
  2. Question 17 · Harder · Choose 2

    A Northern Trail Outfitters app runs fine on developer laptops. In the production container, npm install completes without errors, but the app crashes at startup with Error: Cannot find module 'dayjs'. Which two situations could explain the failure? Choose 2 answers.
    • A.dayjs is listed under devDependencies, and the container sets NODE_ENV=production before running npm install.
    • B.The developer ran npm install dayjs without adding the --save flag, so npm did not record it in package.json.
    • C.The developer installed it with npm install dayjs --no-save, so it exists only in their local node_modules folder.
    • D.package.json lists dayjs with the caret range ^1.11.10 instead of an exact version.
    • E.The team committed package-lock.json to source control alongside package.json.
    Show the answer and explanation
    Correct answers: A. dayjs is listed under devDependencies, and the container sets NODE_ENV=production before running npm install.; C. The developer installed it with npm install dayjs --no-save, so it exists only in their local node_modules folder.
    When NODE_ENV is set to production, npm does not install modules listed in devDependencies (the omit config defaults to dev), so a runtime package saved as a dev dependency is missing in production. --no-save prevents saving to dependencies, so the package sits in the developer's local node_modules but never reaches package.json or the container. npm saves installed packages to dependencies by default (the save config defaults to true), so leaving out --save does not explain the failure. A caret range still installs a matching version, and package-lock.json is intended to be committed so every environment installs the same tree.

Testing

7% of the exam
  1. Question 18 · Easier

    Cloud Kicks offers a loyalty program to customers who are 18 or older. A developer wrote the function and unit test below, and the test passes.
    const assert = require('node:assert/strict');
    
    function isEligible(age) {
        return age > 18;
    }
    
    assert.strictEqual(isEligible(30), true);
    assert.strictEqual(isEligible(12), false);
    Which additional assertion makes the test effective at catching the defect in isEligible()?
    • A.assert.strictEqual(isEligible(65), true);
    • B.assert.strictEqual(isEligible(17), false);
    • C.assert.strictEqual(isEligible(18), true);
    • D.assert.ok(typeof isEligible(30) === 'boolean');
    Show the answer and explanation
    Correct answer: C. assert.strictEqual(isEligible(18), true);
    The requirement includes customers who are exactly 18, but age > 18 returns false for 18, so an assertion at the boundary that expects isEligible(18) to be true fails and exposes the off-by-one defect (the fix is age >= 18). Checking 65 repeats the adult case already covered by 30 and passes with the defective code. Checking 17 is a sensible boundary on the other side, but 17 > 18 is false, so it also passes with the defective code. Checking that the result is a boolean verifies the return type, not the eligibility rule. Effective unit tests exercise the values at and around each boundary of a condition.

Where to go after these 18 questions

Ready for a full JavaScript Developer practice exam?

Take a timed 60-question exam drawn from all 300 reviewed questions in the real exam's section mix, then drill the sections you miss.