Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

JavaScript (ES2026)  Module 4 – Functions, scope and closures

Parameters, defaults and rest parameters

Use default parameters, rest parameters and spread in JavaScript, see when defaults are evaluated and why null skips them, and replace long parameter lists.

  • Beginner
  • 16 minutes
  • Examples run with Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot
Free lesson, Pro answers: 16 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Use default parameters, rest parameters and spread arguments
  • Explain when default values are evaluated, and which arguments trigger them
  • Use an options object instead of long parameter lists
  • Avoid the argument-count limit of spread on large arrays

Before you start

What you’ll learn · Before you start

What you will learn

  • Use default parameters, rest parameters and spread arguments
  • Explain when default values are evaluated, and which arguments trigger them
  • Use an options object instead of long parameter lists
  • Avoid the argument-count limit of spread on large arrays

Before you start

On this page

A parameter is a name in a function’s definition, and an argument is the value a call passes for it. JavaScript does not make the two match: when a call passes fewer arguments than the function has parameters, the missing ones are undefined, and extra arguments are dropped unless the function asks for them. Three features build on that. A default parameter, function greet(name = 'guest'), supplies a value when its argument is missing or undefined, and it is evaluated afresh on every call that needs it. A rest parameter, function total(...amounts), collects the remaining arguments into a real array. Spread in a call, Math.max(...scores), does the opposite: it passes an array’s elements as separate arguments. With destructuring, they let one options object replace a long list of positional parameters, which is where this lesson ends.

Parameters and arguments do not have to match

Fewer and more arguments than parameters JavaScript · missing-and-extra.mjs
// A call may pass fewer arguments than the function has parameters, or more.
function describe(name, city) {
  return `${name} from ${city}`;
}

console.log(describe('Asha', 'Pune'));
console.log(describe('Asha'));                  // city is undefined
console.log(describe('Asha', 'Pune', 'India')); // the third argument is ignored
console.log(describe());
console.log(describe.length); // two declared parameters

Output

Asha from Pune
Asha from undefined
Asha from Pune
undefined from undefined
2

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node missing-and-extra.mjs

A call with one argument leaves city as undefined, which the template turns into the text “undefined”: no error, just a wrong sentence. A call with three arguments ignores the third, and a call with none leaves both parameters undefined. The function’s length, 2, is the number of parameters it declares; it says nothing about the call. That freedom is convenient and dangerous in equal measure, and the features below are the tools for using it on purpose.

Default parameters

A default is written after the parameter with =. It is used when the argument is undefined, whether the call left it out or passed undefined explicitly, and in no other case:

Which arguments trigger a default JavaScript · defaults.mjs
// A default applies when its argument is missing or undefined, and only then.
function greet(name = 'guest', greeting = 'Namaste') {
  return `${greeting}, ${name}`;
}

console.log(greet('Ravi', 'Hello'));
console.log(greet('Ravi'));            // greeting missing
console.log(greet());                  // both missing
console.log(greet(undefined, 'Hi'));   // undefined counts as missing
console.log(greet(null));              // null is a value: it is kept
console.log(greet(''));                // so is the empty string
console.log(greet(0));                 // and 0

Output

Hello, Ravi
Namaste, Ravi
Namaste, guest
Hi, guest
Namaste, null
Namaste, 
Namaste, 0

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node defaults.mjs

null, the empty string and 0 are values, so they are kept: greet(null) says “Namaste, null”. That matters most for data that comes from outside the program. JSON has null but no undefined, so a form or an API that sends "name": null gets past every default. When null should also mean “use the default”, convert it where the data enters the program, with the nullish operator: greet(body.name ?? undefined), or const name = body.name ?? 'guest'.

Older code wrote defaults inside the body, as name = name || 'guest'. That version also replaces '', 0 and false, because || tests for any falsy value, so it turns a legitimate 0 into the default. Defaults in the parameter list say exactly what they mean.

Defaults are evaluated on every call

A default is an expression, and the engine evaluates it each time a call needs it, at the moment the call binds its parameters. A default can therefore call a function, build an object, or use the parameters before it:

When defaults run JavaScript · defaults-timing.mjs
// Defaults are evaluated at call time, on every call that needs them. A fake clock makes the output stable.
let clockCalls = 0;
const clock = {
  now() {
    clockCalls += 1;
    return 1000 * clockCalls;
  },
};

function stamp(event, at = clock.now()) {
  return `${event} at ${at}`;
}

console.log(stamp('login'));
console.log(stamp('save'));
console.log(stamp('import', 42)); // an argument was given: the default is not evaluated
console.log(`clock read ${clockCalls} times`);

// A default object or array is a new one on each call, never shared between calls.
function addTag(tag, tags = []) {
  tags.push(tag);
  return tags;
}
console.log(JSON.stringify(addTag('urgent')), JSON.stringify(addTag('billing')));

// A default may use the parameters before it, but not the ones after it.
function range(start, end = start + 3) {
  return `${start}..${end}`;
}
console.log(range(5), range(5, 6));

function backwards(first = second, second = 1) {
  return first;
}
try {
  backwards();
} catch (error) {
  console.log(error.name);
}

Output

login at 1000
save at 2000
import at 42
clock read 2 times
["urgent"] ["billing"]
5..8 5..6
ReferenceError

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node defaults-timing.mjs

  • stamp() reads the clock once for each call that leaves at out. The call with 42 never evaluates the default, which is why the clock was read twice, not three times.
  • addTag() gets a new, empty array on every call, so the second call does not see the first call’s tag.
  • range(5) uses the earlier parameter start in the default of end. Parameters are bound from left to right, though, so a default cannot use a parameter that comes after it: backwards() reaches second before it has a value and throws a ReferenceError.

Coming from Python

Python evaluates a default once, when def runs, and the Python tutorial warns that a list or dictionary used as a default is therefore shared by every call. JavaScript evaluates the default on each call, so tags = [] is safe here, and a default such as at = clock.now() gives each call its own time.

Rest parameters

A parameter written with three dots in front, ...amounts, is a rest parameter: it collects every argument that has no parameter of its own into a new array. It must be the last parameter, and a function can have only one.

Collecting arguments with a rest parameter JavaScript · rest.mjs
// A rest parameter collects the remaining arguments into a real array.
function total(...amounts) {
  return amounts.reduce((sum, amount) => sum + amount, 0);
}
console.log(total(), total(250), total(250, 120, 80));

function logLine(level, ...parts) {
  return `[${level}] ${parts.join(' ')} (${parts.length} parts)`;
}
console.log(logLine('warn', 'disk', 'at', '91%'));

// The older arguments object: array-like, but not an array.
function oldStyle() {
  return `${arguments.length} arguments, isArray ${Array.isArray(arguments)}, typeof map ${typeof arguments.map}`;
}
console.log(oldStyle('a', 'b', 'c'));

// length counts only the parameters before the first default or rest parameter.
function shape(a, b = 2, ...more) {
  return [a, b, ...more];
}
console.log(total.length, logLine.length, shape.length);

Output

0 250 450
[warn] disk at 91% (3 parts)
3 arguments, isArray false, typeof map undefined
0 1 1

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node rest.mjs

total() with no arguments gets an empty array and returns 0, the start value of reduce(). logLine() takes one ordinary parameter and collects the rest, the usual shape for functions such as loggers and formatters.

Before rest parameters, functions read the arguments object, which every regular function still has. It is array-like (it has length and numbered elements) but not an array, so array methods such as map are missing, and in strict code, which includes every module, it no longer changes when a parameter is reassigned. Arrow functions have no arguments of their own at all, which the lesson on arrow functions shows. A rest parameter is a real array and is visible in the signature, so prefer it in new code.

The last line shows the rule for length: it counts the parameters before the first one with a default or the rest parameter, so shape(a, b = 2, ...more) has length 1.

report('Disk', undefined, 'full', 'at 91%') fills title, then level from its default, then lines with the rest, before the body runs.The callreport('Disk', undefined, 'full', 'at 91%')1. title = 'Disk'the first argument2. The second argument is undefined,so the default runs: level = 'info'3. lines = ['full', 'at 91%']the rest parameter takes what is left4. The body runswith all three parameters set

How a call fills the parameters, in order

Text description of the diagram

The diagram follows one call of `function report(title, level = 'info', ...lines)` from top to bottom.

  1. The call is `report('Disk', undefined, 'full', 'at 91%')`.
  2. The first parameter, `title`, gets the first argument, `'Disk'`.
  3. The second argument is `undefined`, so the default of `level` is evaluated, and `level` becomes `'info'`. Had the argument been `null`, `level` would be `null`.
  4. The rest parameter `lines` collects every argument that is left into a new array, `['full', 'at 91%']`.
  5. Only then does the body run, with all three parameters set.

Spread in calls

Three dots in a call, rather than in a definition, spread an array (or any iterable, such as a string or a Set) into separate arguments:

Spreading arrays and strings into a call JavaScript · spread.mjs
// Spread in a call passes an array's elements as separate arguments.
const scores = [72, 95, 64, 88];
console.log(Math.max(...scores), Math.min(...scores));
console.log(Math.max(scores)); // the whole array as one argument: NaN

// With no arguments at all, max and min return their identity values.
console.log(Math.max(), Math.min());
const noScores = [];
console.log(Math.max(...noScores));

// Spread can be mixed with ordinary arguments, and works on any iterable.
function initials(first, middle, last) {
  return `${first}.${middle}.${last}.`;
}
console.log(initials(...'RKN'));
console.log(Math.max(50, ...scores, 99));

Output

95 64
NaN
-Infinity Infinity
-Infinity
R.K.N.
99

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node spread.mjs

Math.max(scores) passes the array as one argument, which Math.max() converts to a number and gets NaN; Math.max(...scores) passes four numbers. Called with no arguments, Math.max() returns -Infinity and Math.min() returns Infinity, the values that every number beats, so the maximum of an empty array is -Infinity rather than an error. Check for an empty array before you show such a result to anyone.

Spread has a size limit

Every spread element becomes one argument of the call, and engines limit how many arguments a call can have. Here is the same maximum worked out with spread and with a loop, for four array sizes:

Spread against a loop on large arrays JavaScript · spread-limit.mjs
// Spread turns every element into a separate argument, and engines limit how many arguments a call may have.
function maxOf(values) {
  try {
    return String(Math.max(...values));
  } catch (error) {
    return `${error.name}: ${error.message}`;
  }
}

// A loop has no such limit.
function maxByLoop(values) {
  let best = -Infinity;
  for (const value of values) {
    if (value > best) best = value;
  }
  return best;
}

for (const size of [60000, 70000, 100000, 150000]) {
  const values = Array.from({ length: size }, (_, i) => i % 1000);
  console.log(`${size} values: spread ${maxOf(values)} | loop ${maxByLoop(values)}`);
}

Output

60000 values: spread 999 | loop 999
70000 values: spread 999 | loop 999
100000 values: spread 999 | loop 999
150000 values: spread RangeError: Maximum call stack size exceeded | loop 999

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node spread-limit.mjs

Version note

Pressing Run executes the file in QuickJS (quickjs-emscripten 0.32.0). It accepts at most 65,534 arguments per call, so there the spread already fails at 70,000 values: RangeError: too many arguments in function call (only 65534 allowed).

In your browser, QuickJS (quickjs-emscripten 0.32.0) prints:

60000 values: spread 999 | loop 999
70000 values: spread RangeError: too many arguments in function call (only 65534 allowed) | loop 999
100000 values: spread RangeError: too many arguments in function call (only 65534 allowed) | loop 999
150000 values: spread RangeError: too many arguments in function call (only 65534 allowed) | loop 999

On Node.js 24.21.0, spreading 100,000 values worked and 150,000 failed with “Maximum call stack size exceeded”: V8 places a call’s arguments on its call stack, and that many of them do not fit. The exact limit depends on the engine, its stack size and how deep the program already is, so it is not a number to design around. For arrays whose size you do not control, such as rows from a file or a database, use a loop or reduce(), which work for any length.

Options objects instead of long parameter lists

A function with many parameters is hard to call correctly: the call createInvoiceOld('Asha Traders', 120000, 'INR', 15, true) does not say which number is which, and swapping two arguments is not an error. Taking one object and destructuring it in the signature names every value at the call site:

Five positional parameters, then one options object JavaScript · options-object.mjs
// Before: five positional parameters. The call does not say which value is which.
function createInvoiceOld(customer, amountPaise, currency, dueDays, sendEmail) {
  return `${customer}: ${amountPaise} ${currency}, due in ${dueDays} days, email ${sendEmail}`;
}
console.log(createInvoiceOld('Asha Traders', 120000, 'INR', 15, true));
console.log(createInvoiceOld('Asha Traders', 120000, 15, 'INR', true)); // two arguments swapped, no error

// After: one options object, destructured in the signature, with defaults for the optional fields.
function createInvoice({ customer, amountPaise, currency = 'INR', dueDays = 30, sendEmail = false } = {}) {
  if (customer === undefined || amountPaise === undefined) {
    throw new TypeError('createInvoice needs customer and amountPaise');
  }
  return `${customer}: ${amountPaise} ${currency}, due in ${dueDays} days, email ${sendEmail}`;
}
console.log(createInvoice({ customer: 'Asha Traders', amountPaise: 120000, dueDays: 15, sendEmail: true }));
console.log(createInvoice({ amountPaise: 99900, customer: 'Ravi Stores' })); // any order; defaults fill the rest

try {
  createInvoice(); // the = {} default gives an empty object, so the function's own check runs
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}

// Without = {}, a call with no argument fails inside the destructuring, before the body runs.
function createInvoiceNoDefault({ customer, amountPaise }) {
  return `${customer}: ${amountPaise}`;
}
try {
  createInvoiceNoDefault();
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}

Output

Asha Traders: 120000 INR, due in 15 days, email true
Asha Traders: 120000 15, due in INR days, email true
Asha Traders: 120000 INR, due in 15 days, email true
Ravi Stores: 99900 INR, due in 30 days, email false
TypeError: createInvoice needs customer and amountPaise
TypeError: Cannot destructure property 'customer' of 'undefined' as it is undefined.

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node options-object.mjs

Version note

The browser runner’s QuickJS describes the last failure as TypeError: cannot convert to object, while Node.js and Chrome print “Cannot destructure property ‘customer’ of ‘undefined’ as it is undefined”. Either way, there was no object to read customer from.

In your browser, QuickJS (quickjs-emscripten 0.32.0) prints:

Asha Traders: 120000 INR, due in 15 days, email true
Asha Traders: 120000 15, due in INR days, email true
Asha Traders: 120000 INR, due in 15 days, email true
Ravi Stores: 99900 INR, due in 30 days, email false
TypeError: createInvoice needs customer and amountPaise
TypeError: cannot convert to object
  • { customer, amountPaise, currency = 'INR', dueDays = 30, sendEmail = false } picks the properties out of the argument, and each property can have its own default, used when the property is missing or undefined.
  • The = {} after the pattern is a default for the whole argument: a call with no argument gets an empty object, so the function reaches its own check and throws a clear error. Without it, as createInvoiceNoDefault() shows, the call fails inside the destructuring with an error that names the pattern, not the mistake.
  • Required values have no default, and the function checks them itself.
Positional parameters or one options object
Criterion Positional parametersOne options object
A call reads like createInvoice('Asha', 120000, 'INR', 15, true)createInvoice({ customer: 'Asha', amountPaise: 120000, dueDays: 15 })
Order of the values Fixed; swapping two is silentAny order; each value is named
Leaving one value out Pass undefined for each one before itLeave the property out
Adding a value later At the end only, or every call changesA new property with a default
When to choose One to three parameters whose meaning is clear from their positionOptional settings, flags, or more than three values
JSON Formatter An options object often arrives as JSON: format it to check which fields are null, which are missing, and which defaults will apply.

Interview questions

Fresher · When does a default parameter value apply in JavaScript?

Only when the argument is undefined: either the call left it out, as in greet(), or it passed undefined explicitly, as in greet(undefined, 'Hi'). Every other value is kept, including null, 0, '' and false, so greet(null) gets null. The default is an expression evaluated at call time, on each call that needs it, so at = Date.now() gives every call its own time and tags = [] gives every call a new array. A default can use the parameters before it, such as end = start + 10, but not the ones after it, which throws a ReferenceError. Data from JSON is the usual trap: JSON has null but no undefined, so convert null where the data enters the program, for example with ??.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    A teammate speeds up a lookup with function priceOf(sku, cache = new Map()), which checks the cache first and stores every price it fetches. In production the database still sees every single lookup. Explain why the cache never hits, where it should live instead, and how a test would have caught it.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A dashboard computes Math.max(...readings) over a day of sensor readings. It worked for months, then a busy day crashed it with "RangeError: Maximum call stack size exceeded", although nothing recursive runs. Explain the mechanism, roughly where the limit is, and how you fix it and keep it fixed.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A call may pass fewer arguments than there are parameters (the rest are undefined) or more (they are dropped).
  • A default applies only to undefined, missing or explicit. null, 0 and '' are kept; convert null at the edge of the program with ?? when it should mean “use the default”.
  • Defaults are evaluated on every call that needs them, left to right, so they can use earlier parameters and never share an array between calls.
  • ...rest collects the remaining arguments into a real array; prefer it to the old arguments object, which arrow functions do not have.
  • fn(...array) spreads an array into arguments. Math.max() with nothing is -Infinity, and very large arrays overflow the argument limit: use a loop for data of unknown size.
  • Prefer one destructured options object, ending in = {}, over more than three positional parameters.

Exercise

Exercise · Easy · JavaScript

A logger with an options object and a rest parameter

Rewrite createLogger() in logger.mjs so that it takes one options object with defaults, and returns a function that logs with a rest parameter.

  • createLogger({ prefix = '', level = 'info', write = console.log } = {}) accepts any of the three options, in any order, or no argument at all. write is the function that receives each finished line; the tests pass their own, so that they can read what was written.
  • It returns log(messageLevel, ...parts). When messageLevel is at or above the logger's level, log calls write once with the line prefix + '[' + messageLevel + '] ' followed by the parts joined with single spaces, and returns true. Below the level it writes nothing and returns false.
  • The levels, from lowest to highest, are 'debug', 'info', 'warn' and 'error'. An unknown level, in the options or in a call of log, throws a RangeError.

So createLogger({ prefix: 'api: ', level: 'warn', write }) gives a log for which log('error', 'timeout after', 3, 'tries') writes api: [error] timeout after 3 tries, and log('info', 'started') writes nothing.

Starter code · logger.mjs

// The logger of the exercise for lesson javascript/parameters-defaults-and-rest. It still takes three positional
// parameters without defaults, and its log function takes the parts as one array.

export const LEVELS = ['debug', 'info', 'warn', 'error'];

export function createLogger(prefix, level, write) {
  return function log(messageLevel, parts) {
    write(prefix + '[' + messageLevel + '] ' + parts.join(' '));
    return true;
  };
}
The sample tests · logger.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { createLogger } from './logger.mjs';

function recorder() {
  const lines = [];
  return { lines, write: (line) => lines.push(line) };
}

test('writes at or above the level and skips the rest', () => {
  const out = recorder();
  const log = createLogger({ level: 'warn', write: out.write });
  assert.equal(log('warn', 'disk', '91%'), true);
  assert.equal(log('error', 'down'), true);
  assert.equal(log('info', 'started'), false);
  assert.deepEqual(out.lines, ['[warn] disk 91%', '[error] down']);
});

test('the prefix comes first and every part is joined', () => {
  const out = recorder();
  const log = createLogger({ write: out.write, level: 'debug', prefix: 'api: ' });
  log('error', 'timeout after', 3, 'tries');
  assert.deepEqual(out.lines, ['api: [error] timeout after 3 tries']);
});

test('the level defaults to info', () => {
  const out = recorder();
  const log = createLogger({ write: out.write });
  assert.equal(log('debug', 'details'), false);
  assert.equal(log('info', 'ready'), true);
  assert.deepEqual(out.lines, ['[info] ready']);
});

test('createLogger() works with no argument', () => {
  const log = createLogger();
  assert.equal(typeof log, 'function');
  assert.equal(log('debug', 'not written'), false);
});

test('unknown levels throw a RangeError', () => {
  assert.throws(() => createLogger({ level: 'verbose' }), RangeError);
  const log = createLogger({ write: () => {} });
  assert.throws(() => log('fatal', 'x'), RangeError);
});
A hint

Destructure the options in the signature, function createLogger({ prefix = '', level = 'info', write = console.log } = {}), and give the inner function a rest parameter, function log(messageLevel, ...parts). A small helper that returns a level's position in LEVELS with indexOf(), and throws a RangeError when it is -1, serves both checks: compare the message's position with the logger's.

The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Check yourself

6 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 6 What does this program print?

    Read the code, then choose one answer.

    function label(text = 'untitled') {
      return `[${text}]`;
    }
    
    console.log(label(), label(undefined), label(null), label(''));
    Show the answer to question 1

    Answer: [untitled] [untitled] [null] []

    A default applies only when the argument is undefined, whether it was left out or passed explicitly. null and the empty string are values, so they are kept.

  2. Question 2 of 6 What does this program print?

    Read the code, then choose one answer.

    function add(item, list = []) {
      list.push(item);
      return list.length;
    }
    
    console.log(add('a'), add('b'), add('c', ['x']));
    Show the answer to question 2

    Answer: 1 1 2

    The default [] is evaluated on every call that needs it, so the first two calls each get a new, empty array. The third call passes its own array, which already holds one item.

  3. Question 3 of 6 What is the length of function connect(host, port = 443, ...options) {}?

    Choose one answer.

    Show the answer to question 3

    Answer: 1

    length counts the parameters before the first one that has a default or is a rest parameter: only host. It is a property of the function and never depends on a call.

  4. Question 4 of 6 Which statements about function f(...values) {} are true? Choose every true one.

    Choose every answer that is right.

    Show the answer to question 4

    Answer:

    • values is a real array, so values.map() works
    • Arrow functions can use rest parameters, although they have no arguments object
    • f() with no arguments gives values an empty array

    A rest parameter always gets a new array, empty when nothing is left, and it must be the last parameter. Arrow functions have no arguments of their own, but rest parameters work in them like in any function.

  5. Question 5 of 6 const readings = []; What does Math.max(...readings) return?

    Choose one answer.

    Show the answer to question 5

    Answer: -Infinity

    Spreading an empty array passes no arguments, and Math.max() with no arguments returns -Infinity, which every number is greater than. Check for an empty array before showing such a maximum.

  6. Question 6 of 6 What happens on the last line?

    Read the code, then choose one answer.

    function connect({ host, port = 443 }) {
      return `${host}:${port}`;
    }
    
    connect();
    Show the answer to question 6

    Answer: It throws a TypeError, because there is no object to destructure

    The pattern tries to read host from the argument, which is undefined, and that throws a TypeError before the body runs. Writing { host, port = 443 } = {} gives the missing argument a default empty object, and the call would return "undefined:443".

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.