JavaScript: Operators

Master every operator in JavaScript: from basic arithmetic to nullish coalescing, optional chaining, spread, and rest.

Arithmetic Operators

Arithmetic operators perform mathematical calculations. JavaScript supports the standard four plus modulo (%) and exponentiation (**) introduced in ES2016.

Arithmetic Operators

Standard math operations, with two worth noting: % gives remainder, ** raises to a power.

  • +: addition (also concatenation when a string is involved)
  • -: subtraction
  • *: multiplication
  • /: division (always returns a float: 7 / 2 === 3.5)
  • %: remainder (modulo): 10 % 3 === 1
  • **: exponentiation: 2 ** 8 === 256

Arithmetic Operators

% is useful for checking even/odd; ** replaces Math.pow().

Assignment Operators

Assignment operators store a value in a variable. Compound assignment operators combine an arithmetic operation with assignment, making updates concise.

Assignment Operators

Compound assignments are shorthand: x += 5 means x = x + 5.

  • =: basic assignment
  • +=: add and assign: x += 5
  • -=: subtract and assign: x -= 5
  • *=: multiply and assign: x *= 2
  • /=: divide and assign: x /= 2
  • %=: modulo and assign: x %= 3
  • **=: exponentiate and assign: x **= 2

Compound Assignment Operators

Each line updates score in place: run to trace through the chain.

Comparison Operators

Comparison operators evaluate two values and return a boolean. The most important distinction is between loose equality (==) which allows type coercion, and strict equality (===) which does not.

== vs ===

Always use === in production: == can produce unexpected results through coercion.

  • ===: strict equality: same value AND same type
  • !==: strict inequality: different value OR different type
  • ==: loose equality: converts types before comparing
  • !=: loose inequality
  • >, <, >=, <=: work numerically or lexicographically on strings

Strict vs Loose Equality

5 == "5" is true: 5 === "5" is false. Always use === to avoid coercion surprises.

Logical Operators

Logical operators combine boolean expressions. In JavaScript they also use short-circuit evaluation: they stop as soon as the result is determined and return the actual value that caused the stop, not just true/false.

&&, ||, !

Logical operators short-circuit and return the deciding operand, not always a boolean.

  • &&: returns the first falsy value, or the last value if all are truthy
  • ||: returns the first truthy value, or the last value if all are falsy
  • !: negates a boolean; !! converts any value to boolean
  • Short-circuit: false && heavyFn(): heavyFn is never called

Short-Circuit Evaluation

|| is commonly used for default values, but ?? is safer (see Nullish Coalescing).

Unary Operators

Unary operators act on a single operand. They include increment/decrement, numeric conversion, typeof, and delete.

Unary Operators

Operate on one value: prefix vs postfix placement matters for ++ and --.

  • ++ prefix (++x): increments then returns new value
  • ++ postfix (x++): returns current value then increments
  • +x: converts x to a number: +"5" === 5
  • -x: negates x
  • typeof: returns a string type label
  • delete: removes a property from an object

Unary Operators

Prefix ++ vs postfix ++ differ in when the return value is read.

Ternary Operator

The ternary operator is the only JavaScript operator that takes three operands. It is a concise inline alternative to an if/else when assigning or returning one of two values.

? : (Ternary)

condition ? valueIfTrue : valueIfFalse: one expression, two possible results.

  • Syntax: condition ? expr1 : expr2
  • Best for simple, readable two-branch choices
  • Avoid nesting ternaries: use if/else for complex logic
  • Can be used inside template literals: `Hello, ${isAdmin ? "Admin" : "User"}`

Ternary Operator

Great for simple inline choices: switch to if/else when you need more than two branches.

Nullish Coalescing Operator (??)

The nullish coalescing operator (??) returns the right-hand side only when the left is null or undefined. This makes it safer than || for default values when 0 or "" are valid values.

?? vs ||

Use ?? when 0 or empty string are valid values that should not trigger the default.

  • a ?? b: returns b only if a is null or undefined
  • a || b: returns b if a is any falsy value (0, "", false, null, undefined)
  • Use ?? for configuration defaults where 0 or "" are legitimate inputs
  • Can be combined with ??= (nullish assignment): x ??= "default"

?? vs || for Default Values

volume ?? 50 keeps 0; volume || 50 replaces it: a critical difference.

Optional Chaining Operator (?.)

Optional chaining (?.) safely accesses deeply nested properties. If any part of the chain is null or undefined, the whole expression short-circuits to undefined instead of throwing a TypeError.

?. (Optional Chaining)

Access nested properties safely: returns undefined instead of crashing.

  • obj?.prop: returns undefined if obj is null/undefined
  • obj?.method(): calls the method only if it exists
  • arr?.[0]: safely accesses an array index
  • Combine with ?? to provide a fallback: user?.name ?? "Guest"

Optional Chaining

?. turns a TypeError crash into a clean undefined: combine with ?? to provide a fallback.

Spread Operator (...)

The spread operator (...) expands an iterable (array, string, or object) into individual elements. It is used for copying, merging, and passing arguments.

Spread (...)

Unpacks an iterable into individual elements at the call site.

  • Copy an array: [...original], shallow clone
  • Merge arrays: [...a, ...b]
  • Copy/merge objects: { ...obj, newKey: value }
  • Pass array as function arguments: Math.max(...nums)

Spread Operator

Later spread properties overwrite earlier ones: useful for applying overrides on top of defaults.

Rest Operator (...)

The rest operator uses the same ... syntax as spread but does the opposite: it collects multiple values into a single array. It appears in function parameters and destructuring assignments.

Rest (...)

Gathers remaining values into an array: the inverse of spread.

  • In function params: collects all extra arguments into an array
  • Must be the last parameter: function fn(a, b, ...rest)
  • In destructuring: const [first, ...remaining] = arr
  • Replaces the old arguments object: rest is a real array with all array methods

Rest Operator

Rest collects; spread expands: same syntax, opposite direction.

Operator Precedence

Operator precedence determines the order in which operators are evaluated when an expression contains multiple operators. Higher precedence operators are evaluated first. Use parentheses to override the default order.

Operator Precedence

When in doubt, add parentheses: they are always evaluated first and make intent clear.

  • Highest: Grouping () → Member access . → Function call ()
  • Unary: !, ++, --, typeof
  • Arithmetic: *** / %+ -
  • Comparison: < > <= >==== !== == !=
  • Logical: &&||??
  • Lowest: Assignment = += -=

Operator Precedence

Parentheses cost nothing: use them to make complex expressions unambiguous.

PriorityOperator(s)Example
1 (highest)Grouping ()(2 + 3)
2Member . / ?.obj.name
3Unary ! ++ -- typeof!flag, ++x
4Exponentiation **2 ** 8
5Multiply * / %10 * 3
6Add / Subtract + -5 + 2
7Comparison < > <= >=a > b
8Equality === !==a === b
9Logical AND &&a && b
10Logical OR ||a || b
11Nullish ??a ?? b
12 (lowest)Assignment = += -=x = 5

String Concatenation vs Addition

The + operator is overloaded: it performs numeric addition when both operands are numbers, but switches to string concatenation the moment either operand is a string. This is the most common source of accidental coercion bugs.

+ Operator Overloading

+ is the only arithmetic operator that concatenates: all others (- * /) always convert to numbers.

  • Number + Number → addition: 5 + 3 → 8
  • String + anything → concatenation: "5" + 3 → "53"
  • Use Number() or unary + to force numeric addition
  • Template literals are cleaner than + for building strings: `Hello, ${"{name}"}`

+ Concatenation vs Addition

Only + is ambiguous: subtract, multiply, and divide always produce numbers.

Knowledge Check

1. What is the result of 2 ** 10 in JavaScript?

2. What is the difference between == and ===?

3. What does the ?? operator do?

4. What is the result of "5" + 3 in JavaScript?

5. What does optional chaining (?.) do when a property does not exist?

6. What does the rest operator (...) do in a function parameter list?

7. Which of the following correctly uses the ternary operator?

8. What is the result of !!"" (double negation of an empty string)?

9. Which operator has the highest precedence?

10. What does the spread operator do when used with an array?