Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~28 min· topic 1 of 7

Topic 2.1

Operators

In one line

Operators are the symbols that combine values into new values: + - * / % ** for maths, = and += to store results, ++ and -- to count, < > <= >= to compare, and + again to join strings, all evaluated in a fixed order called precedence.

Think of it like this

A calculator. The numbers you type are the values, and the buttons +, −, × and ÷ are the operators: each one takes the numbers next to it and produces a new number. A good calculator also knows that 2 + 3 × 4 is 14, not 20, because multiplication happens first. JavaScript works the same way, with a few extra buttons and a few surprises.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Operator
A symbol like +, * or < that takes values and produces a new value.
Operand
A value an operator works on. In 7 + 2, the operands are 7 and 2.
Expression
Any piece of code that produces a value, like 7 + 2, x, or "hi".
Unary / binary
A unary operator takes one value (-x, !x); a binary operator takes two (a + b).
Remainder (%)
What is left over after dividing: 7 % 2 is 1.
Concatenation
Joining strings end to end: "ab" + "cd" gives "abcd".
Compound assignment
A shortcut like x += 5 that means x = x + 5.
Precedence
The order operators run in when there are several, like * before +.
Associativity
Which side goes first when operators have the same precedence: usually left to right.

Step by step

01Do the maths

The arithmetic operators work like school maths, with two additions: % gives the remainder and ** raises to a power. / never throws away the decimal part.

maths.jswhole filejavascript
console.log(7 / 2);   // 3.5
console.log(7 % 2);   // 1  (7 = 3 * 2 + 1)
console.log(2 ** 10); // 1024
console.log(Math.trunc(7 / 2)); // 3, whole-number division

02Watch out for + with strings

If either side of + is a string, + joins instead of adding. Values from inputs, URLs and storage are strings, so convert them first with Number(...) (Topic 1.5 — Type Conversion).

join.jswhole filejavascript
const qty = "2";            // from an <input>: always a string
console.log(qty + 3);         // "23"  joined!
console.log(Number(qty) + 3); // 5     added

03Store and update results

= stores a value. Compound operators update in place: total += price reads total, adds price and stores the result back. count++ adds one.

Prefix and postfix only differ when you use the value in the same expression. Keep ++ on its own line and the difference never bites.

update.jswhole filejavascript
let total = 0;
total += 40;  // 40
total *= 3;   // 120
let count = 0;
count++;      // 1

04Compare values

Comparisons produce booleans, ready for an if (Topic 2.3). Numbers compare by size; strings compare letter by letter by character code; a string against a number becomes a number comparison.

05Let precedence decide the order, or decide it yourself

The engine builds a tree from your expression using the precedence table, then works from the leaves up. Higher-precedence operators sit lower in the tree and run first.

Let precedence decide the order, or decide it yourselfdiagram
Rendering diagram…

Try it yourself

  1. 1

    Predict the joins

    In the second example, add console.log("3" + 4 + 5, 3 + 4 + "5");. Write your prediction down, then run. (Answer: 345 75.)

  2. 2

    Fix the quantity

    Change the input's value to 10 and run. The red line shows 103; the green line shows 13. Change the red line's code so both are correct.

  3. 3

    Move the parentheses

    In the last example, change 2 ** 3 ** 2 to (2 ** 3) ** 2. Predict first: is it still 512? (It's 64.)

Code & diagrams

The arithmetic operators New tab

`%` keeps the sign of the left number and works on decimals too. Dividing by zero gives `Infinity` or `NaN`, never an error.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

7 + 2 = 9
7 - 2 = 5
7 * 2 = 14
7 / 2 = 3.5
7 % 2 = 1
2 ** 3 = 8
-7 % 2 = -1
5.5 % 2 = 1.5
1 / 0 = Infinity
0 / 0 = NaN
When + joins instead of adding New tab

Only `+` joins. `-`, `*`, `/` and unary `+` always convert to numbers. Left-to-right order explains `33` vs `123`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

string
33
123
3
10
42 0 NaN
2
Assignment, increment and decrement New tab

Console

(nothing was printed)

Expected console output

score: 8
postfix: 6 5
prefix: 6 6
chained: 0 0
Comparison and precedence New tab

`"10" < "9"` compares text letter by letter; `"10" < 9` converts the string to a number first. `-` runs left to right, `**` right to left.

Console

(nothing was printed)

Expected console output

true true false
true true false
true false
false false false
14
20
3
512
true

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Put a minus sign in front of a power

In the last example, add the line console.log(-2 ** 2); and run.

terminal
$ Console
── what you'll see ──
Uncaught SyntaxError: Unary operator used immediately before exponentiation expression. Parenthesis must be used to disambiguate operator precedence

Break #2

Add up input values without converting

In the second example, add console.log(qty + qty);.

terminal
$ Console
── what you'll see ──
22

Myth vs fact

Myth

% is the modulo operator from maths.

Fact

It's the remainder: the result has the sign of the left operand, so -7 % 2 is -1, while true modulo gives 1. For an always-positive result use ((n % m) + m) % m.

Myth

7 / 2 gives 3 like in some other languages.

Fact

JavaScript has one number type, so / gives 3.5. Use Math.trunc, Math.floor or Math.round to get a whole number on purpose.

Myth

x++ and ++x are the same.

Fact

Both add one to x. They differ in the value the expression gives back: old value for x++, new value for ++x. That matters as soon as you write y = x++.

Myth

You need to memorise the whole precedence table.

Fact

Know the big ones (* before +, comparisons before &&, assignment last) and use parentheses for everything else. Readable code beats clever code.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Under the hood, + follows the spec's ApplyStringOrNumericBinaryOperator: both sides are first converted with ToPrimitive (objects call valueOf/toString), and if either result is a string, it concatenates. That's why [1] + [2] is "12" and {} + [] behaves differently at the start of a line (where {} is read as an empty block).

  • ▸

    Comparisons with null and undefined are inconsistent by design: null >= 0 is true (relational operators convert null to 0) while null == 0 is false (loose equality has its own rules). undefined becomes NaN, so every relational comparison with it is false. Check for missing values explicitly before comparing.

  • ▸

    String comparison with < uses UTF-16 code units, not language rules. To sort or compare words for humans (accents, case, numbers inside text) use a.localeCompare(b) or Intl.Collator (you'll meet these with sorting in Phase 5).

  • ▸

    V8 stores small whole numbers as Smis (small integers) and switches to doubles when a result has a decimal or overflows. Keeping arithmetic in whole numbers in hot loops (for example, cents instead of decimal rupees) avoids both rounding errors and that switch.

Remember this

  1. 1

    An operator is a symbol (or keyword) that takes one or more values and produces a new value. The values it works on are called operands. In 7 + 2, the operator is + and the operands are 7 and 2. An operator with two operands is binary (a * b); one with a single operand is unary (-a, !a, typeof a). A piece of code that produces a value, like 7 + 2 or just 7, is called an expression.

  2. 2

    Arithmetic operators: + add, - subtract, * multiply, / divide, % remainder and ** exponent (power, since ES2016). Division always gives a decimal if needed: 7 / 2 is 3.5, never 3 (there is no separate whole-number division; use Math.trunc(7 / 2) for that). % gives what is left over: 7 % 2 is 1, which is how you test even and odd numbers. Its result takes the sign of the left number, so -7 % 2 is -1: it is a remainder, not the mathematical modulo. Dividing by zero doesn't crash: 1 / 0 is Infinity and 0 / 0 is NaN (see Topic 1.3 — Numbers in Depth).

  3. 3

    + has two jobs. If either operand is a string, it joins (concatenates) them into one string: "Hi " + "Asha" is "Hi Asha" and "5" + 2 is "52". Only when neither side is a string does it add. All the other arithmetic operators (- * / % **) only do maths, so they convert strings to numbers: "5" - 2 is 3. Expressions run left to right, so 1 + 2 + "3" is "33" (1 + 2 is 3 first, then joined with "3"), while "1" + 2 + 3 is "123". The unary plus +value converts to a number: +"42" is 42. This is the number-one beginner bug with form inputs, whose values are always strings.

  4. 4

    Assignment operators store a value in a variable. = assigns; compound assignment combines an operation with the assignment: x += 5 means x = x + 5, and the same works for -=, *=, /=, %= and **=. An assignment is itself an expression whose value is the assigned value, which is why a = b = 0 sets both (it runs right to left). Increment ++ adds 1 and decrement -- subtracts 1. Their position matters when you use the result: postfix x++ gives back the old value then adds, prefix ++x adds first and gives back the new value. Used alone on a line (count++;) they do the same thing.

  5. 5

    Comparison operators <, >, <= and >= give true or false. Two numbers compare as numbers. Two strings compare character by character by their UTF-16 code (the number each character has in the Unicode table), so "apple" < "banana" is true, every capital letter comes before every small one ("Z" < "a" is true) and "10" < "9" is true because "1" comes before "9". If one side is a number and the other a string, the string is converted to a number first, so "10" < 9 is false. Anything compared with NaN is false. (Equality, === and ==, was Topic 1.6.)

  6. 6

    Precedence is the order in which operators run when an expression has several. From first to last, the ones you'll use most: grouping ( ), unary operators (!, -x, +x, typeof, ++, --), then **, then * / %, then + -, then comparisons < > <= >=, then equality === !==, then &&, then || and ??, then the ternary ? :, and assignment last. Operators with the same precedence run left to right (associativity), except ** and assignment, which run right to left: 2 ** 3 ** 2 is 2 ** 9, which is 512. When in doubt, add parentheses: they cost nothing and make your intent clear to the next reader.

Explain it without notes

01

Why does "5" + 2 give "52" while "5" - 2 gives 3?

02

What is the difference between x++ and ++x?

03

What is operator precedence, and how do you control it?

04

Why is "10" < "9" true but "10" < 9 false?

Practice

01

Write a line that prints whether the number n = 17 is even or odd using %.

02

A shop sells pens at 12 rupees. Read the quantity "4" (a string, as from an input), and print Total: 48.

03

Without running it, predict what console.log(3 + 4 * 2 ** 2 - 1) prints, then check.

Trade-offs

  • ↔

    Compact expressions like total += qty * price are clear; long one-liners mixing ++, assignment and comparisons save lines but hide bugs. Split them into named steps.

  • ↔

    Relying on implicit conversion ("5" * 2) works but hides intent; explicit Number() costs a few characters and makes the code obvious.

Done when you can

  • I can use + - * / % ** and predict their results, including decimals and division by zero.

  • I can explain when + joins strings and avoid that bug with form input.

  • I can use +=, ++ and --, and explain prefix vs postfix.

  • I can predict string vs number comparisons.

  • I can work out an expression's order from precedence, and add parentheses to make it clear.