Skip to content
JavaScript js fundamentals 4 min read

Arithmetic Operators

Arithmetic operators are how JavaScript does math, from adding two numbers to computing powers and remainders. They look familiar from school, but JavaScript adds a few wrinkles worth knowing: a single + that doubles as string concatenation, prefix versus postfix increment, and the floating-point quirks that surprise newcomers. Mastering these — and the precedence rules that decide what runs first — keeps your calculations correct and your code readable.

The basic operators

JavaScript has the five operators you’d expect, plus exponentiation (**, added in ES2016). All of them work on numbers and coerce non-numeric operands to numbers where possible.

OperatorNameExampleResult
+Addition7 + 310
-Subtraction7 - 34
*Multiplication7 * 321
/Division7 / 32.333…
%Remainder7 % 31
**Exponentiation2 ** 101024
const a = 7;
const b = 3;

console.log(a + b);  // 10
console.log(a / b);  // 2.3333333333333335
console.log(a % b);  // 1
console.log(2 ** 10); // 1024

Output:

10
2.3333333333333335
1
1024

Note that / always produces a floating-point result — there is no separate integer division. To truncate toward zero, use Math.trunc(a / b); to round down, use Math.floor.

Remainder and exponentiation

The % operator returns the remainder after division, not a true mathematical modulo. The result takes the sign of the dividend (the left operand), which matters for negative numbers.

console.log(10 % 3);   // 1
console.log(-10 % 3);  // -1  (sign follows -10)
console.log(10 % -3);  // 1

// Common use: detect even/odd
const isEven = (n) => n % 2 === 0;
console.log(isEven(4)); // true

For exponentiation, ** is right-associative, so 2 ** 3 ** 2 evaluates as 2 ** (3 ** 2) = 2 ** 9 = 512. It replaces the older Math.pow(2, 9) and reads more naturally.

Gotcha: A unary minus directly in front of a base is a syntax error: -2 ** 2 is rejected. Write (-2) ** 2 (which is 4) or -(2 ** 2) (which is -4) to be explicit.

Unary plus and minus

+ and - also work as unary operators on a single value. Unary minus negates a number; unary plus is the fastest, terse way to coerce a value to a number — it’s equivalent to Number(x).

const str = "42";
console.log(+str);        // 42      (number)
console.log(typeof +str); // "number"
console.log(-str);        // -42

console.log(+"");      // 0
console.log(+"abc");   // NaN
console.log(+true);    // 1

Output:

42
number
-42
0
NaN
1

Increment and decrement

++ adds one and -- subtracts one. Each comes in two forms: prefix (++x) changes the variable and returns the new value; postfix (x++) returns the old value, then changes the variable. The difference only shows when you use the result in the same expression.

let x = 5;
console.log(x++); // 5  → logs old value, then x becomes 6
console.log(x);   // 6

let y = 5;
console.log(++y); // 6  → y becomes 6 first, then logs
console.log(y);   // 6

Output:

5
6
6
6

Tip: When the return value isn’t used (e.g. a for loop counter or a standalone statement), prefix and postfix behave identically — pick whichever your team prefers. These operators only work on variables and properties, never on literals: 5++ is an error.

Operator precedence

When operators mix in one expression, precedence decides the order. Exponentiation binds tighter than *, /, and %, which bind tighter than + and -. Operators of equal precedence (except **) evaluate left to right. Parentheses always override the defaults.

console.log(2 + 3 * 4);     // 14, not 20
console.log(2 ** 3 * 2);    // 16  ((2**3) * 2)
console.log((2 + 3) * 4);   // 20
console.log(10 - 4 - 2);    // 4   (left-to-right)

When in doubt, add parentheses. They cost nothing at runtime and make intent obvious to the next reader.

Number quirks

JavaScript numbers are IEEE-754 double-precision floats, so some decimals can’t be represented exactly. The classic example surprises everyone:

console.log(0.1 + 0.2);            // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);    // false

// Compare with a tolerance instead
const almostEqual = (a, b) => Math.abs(a - b) < Number.EPSILON;
console.log(almostEqual(0.1 + 0.2, 0.3)); // true

// Or round for display
console.log((0.1 + 0.2).toFixed(2)); // "0.30"

Output:

0.30000000000000004
false
true
0.30

A few other values to know: division involving 0 or non-numbers yields special results rather than throwing. 1 / 0 is Infinity, -1 / 0 is -Infinity, and 0 / 0 is NaN. Any arithmetic touching NaN produces NaN, and NaN is famously not equal to itself — use Number.isNaN(x) to test for it. For exact decimal money math, use integers (work in cents) or a library like decimal.js. For integers beyond Number.MAX_SAFE_INTEGER (2^53 − 1), use BigInt literals such as 10n ** 20n.

Best Practices

  • Reach for ** over Math.pow, and prefer Math.trunc/Math.floor for integer division instead of bit hacks.
  • Never compare floating-point results with ===; use Number.EPSILON or .toFixed() for display.
  • Use +value for quick numeric coercion, but Number(value) or parseInt/parseFloat when clarity matters.
  • Parenthesize mixed-operator expressions rather than relying on memory of precedence tables.
  • Avoid postfix ++/-- inside larger expressions where the read-then-mutate behavior can confuse readers.
  • Handle money in integer cents (or BigInt) to sidestep rounding errors entirely.
  • Guard against NaN and Infinity from untrusted input with Number.isFinite() before using a computed value.
Last updated June 1, 2026
Was this helpful?