Arithmetic Operators
JavaScript supports the arithmetic you'd expect — add, subtract, multiply, divide — plus a few that come up less often: modulo, exponentiation, and the increment/decrement shortcuts. The mechanics are simple; the interesting parts are the edge cases around NaN, Infinity and the special behaviour of + with strings.
The six basic operators
10 + 4; // 14 addition 10 - 4; // 6 subtraction 10 * 4; // 40 multiplication 10 / 4; // 2.5 division (always float — no integer division) 10 % 4; // 2 remainder (modulo) 2 ** 10; // 1024 exponentiation (ES2016)
/ always produces a float. If you want integer division, drop the fractional part explicitly:
Math.trunc(10 / 4); // 2 (drop toward zero) Math.floor(10 / 4); // 2 Math.floor(-10 / 4); // -3 (round down — different from trunc for negatives) (10 / 4) | 0; // 2 (bitwise trick — 32-bit only)
Unary plus and unary minus
Used in front of a single operand. - negates; + converts to a number. Unary + is one of the shortest ways to parse a numeric string.
-7; // -7 -(3 - 1); // -2 +"42"; // 42 (string → number) +"42.5"; // 42.5 +""; // 0 (!) +"abc"; // NaN +true; // 1 +false; // 0 +null; // 0 +undefined; // NaN
Increment and decrement
++ adds 1 to a variable, -- subtracts 1. They come in prefix and postfix flavours that differ in what the expression evaluates to.
let a = 5; let b = a++; // postfix: a becomes 6, b gets the OLD value 5 let c = 5; let d = ++c; // prefix: c becomes 6, d gets the NEW value 6 console.log(a, b, c, d);
6 5 6 6
If you use ++ or -- purely for the side effect (a statement on its own line), the prefix/postfix choice doesn't matter. Inside a larger expression — arr[i++], while (--n > 0) — the difference is meaningful and can be confusing. Many style guides discourage mixing ++/-- with other operators on the same line.
The + operator and strings
+ is overloaded. If either operand is a string, both are converted to strings and concatenated. Otherwise, both are converted to numbers and added.
1 + 2; // 3 "1" + 2; // "12" 1 + "2"; // "12" 1 + 2 + "3"; // "33" — left-to-right: (1+2) is 3, then 3+"3" is "33" "1" + 2 + 3; // "123" — string sticks "" + 42; // "42" (tersest way to stringify a number)
NaN — Not a Number
NaN is a special number value that means "this calculation didn't produce a real number". It is contagious: any arithmetic that touches NaN returns NaN.
0 / 0; // NaN
Math.sqrt(-1); // NaN
Number("oops"); // NaN
NaN + 1; // NaN
NaN === NaN; // false (!)
Number.isNaN(NaN); // true — the safe test
Number.isNaN("oops"); // false — Number.isNaN only matches actual NaNUse Number.isNaN(x) to test, not the older global isNaN(x). The global version coerces to a number first, so isNaN("oops") is true — usually not what you want.
Infinity
Numbers too big to represent become Infinity (or -Infinity). You can also produce Infinity deliberately.
1 / 0; // Infinity -1 / 0; // -Infinity Infinity + 1; // Infinity Infinity - Infinity;// NaN 1e308 * 10; // Infinity (overflow) Number.isFinite(42); // true Number.isFinite(Infinity); // false Number.isFinite(NaN); // false
Floating-point reality
Numbers are 64-bit floats (IEEE 754). Some apparently simple decimals can't be represented exactly.
0.1 + 0.2; // 0.30000000000000004 0.1 + 0.2 === 0.3; // false (!) // Compare with a tolerance instead Math.abs((0.1 + 0.2) - 0.3) < 1e-9; // true // Or round for display (0.1 + 0.2).toFixed(1); // "0.3"
Modulo and negative numbers
% returns a value with the sign of the dividend (the left operand). This trips up anyone coming from a language with a true mathematical modulo.
10 % 3; // 1 -10 % 3; // -1 (sign of -10) 10 % -3; // 1 -10 % -3; // -1 // A "positive modulo" helper const mod = (n, m) => ((n % m) + m) % m; mod(-10, 3); // 2
Exponentiation
2 ** 8; // 256 2 ** 0.5; // 1.4142135... (square root) (-2) ** 3; // -8 // -2 ** 3; // SyntaxError — must parenthesise a unary minus on the left of ** Math.pow(2, 8); // 256 — older form, identical result
Numeric separators
Underscores can be used in numeric literals to make long numbers readable. The engine ignores them.
const billion = 1_000_000_000; const mac = 0xff_ee_dd_cc_bb_aa; const binary = 0b1010_0110_1110_0001;
BigInt arithmetic
For integers beyond Number.MAX_SAFE_INTEGER, use BigInt. It supports the same operators, but you can't mix bigint and number in the same expression.
9_007_199_254_740_993n + 1n; // 9007199254740994n 2n ** 64n; // 18446744073709551616n // 1n + 1; // TypeError — mixed types Number(2n ** 32n); // 4294967296 (back to a regular number, if it fits)