JavaScript · Beginner
JavaScript Operators: Arithmetic, Comparison and Logic
In short: Operators combine values: arithmetic (+ - * / % **), assignment (= += -=), comparison (=== !== < >), logical (&& || !) plus the nullish ?? and the ternary ?:. Use === rather than == because == converts types before comparing, and remember that + joins strings whenever one operand is text.
Combining values
An operator takes one or two values and produces a new one. The surprises lie in how they treat mixed types, so this lesson is as much about conversion as about symbols.
Arithmetic: +, -, *, /, % (remainder) and ** (exponent, added in ES2016). Division produces a decimal whenever the numbers do not divide evenly: 7 / 2 is 3.5, and you call Math.floor() or Math.trunc() when you want a whole number. The remainder takes the sign of the left operand, so -7 % 3 is -1. + is the special case: if either operand is a string, the other is converted to text and the two are joined. Every other arithmetic operator converts strings to numbers, so "6" * "7" is 42 while "6" + "7" is "67". ++ and -- add or subtract one in place.
Assignment: = stores a value in a variable. The compound forms +=, -=, *=, /= and %= apply an operator and store the result, so total += 5 means total = total + 5.
Comparison: <, <=, > and >= compare numbers, or compare strings character by character using their code unit values, which puts uppercase letters before lowercase and makes "10" < "9" true. Equality has two forms. === (strict) is true only when the types match and the values match; !== is its opposite. == (loose) first converts both operands to a common type, which is why 5 == "5" and 0 == "" are true. The conversion rules are long and rarely what you meant, so use === and convert explicitly. NaN is not equal to anything, itself included.
Logical: && (and), || (or) and ! (not). && and || return one of their operands, not necessarily a boolean: a || b gives a when a is truthy and otherwise b; a && b gives a when a is falsy and otherwise b. Both short-circuit: the right side is not evaluated when the left side already decides the result. ?? (nullish coalescing, ES2020) is like || but only falls through for null and undefined, so a legitimate 0 or empty string is kept.
The conditional operator condition ? a : b is an expression that picks one of two values. Use it to pick a value, not as a substitute for an if that has side effects. Precedence follows the usual conventions (* before +, comparisons before &&, && before ||). When a line mixes families, add parentheses.
Syntax
a + b a - b a * b a / b a % b a ** b // arithmetic
x += 1 x -= 1 x *= 2 x /= 2 x++ x-- // assignment forms
a === b a !== b a < b a <= b a > b a >= b // comparison (strict)
a == b a != b // loose: converts first, avoid
a && b a || b !a a ?? b // logical and nullish
condition ? valueIfTrue : valueIfFalse // conditional (ternary)
typeof a // also an operatorUse === and !== unless you have a specific reason to want type conversion. Parentheses cost nothing and make precedence obvious.
== versus ===
| Expression | == | === |
|---|---|---|
| 5 == "5" | true | false |
| 0 == "" | true | false |
| 0 == false | true | false |
| null == undefined | true | false |
| null == 0 | false | false |
| "abc" == "abc" | true | true |
Arithmetic on a delivery run
Seventeen boxes are loaded five to a van; the later lines show compound assignment, ++ and what + does with text.
const boxes = 17;
const perVan = 5;
console.log("Full vans:", Math.floor(boxes / perVan));
console.log("Boxes left over:", boxes % perVan);
console.log("Exact division:", boxes / perVan);
console.log("Area of a 4 m square:", 4 ** 2);
let stock = 10;
stock += 3;
stock -= 1;
stock *= 2;
console.log("Stock:", stock);
let count = 0;
count++;
count++;
console.log("Count:", count);
console.log("Text plus number:", "Order " + 42);
console.log("Number plus number:", 40 + 2);
console.log("Strings times strings:", "6" * "7");
console.log(-7 % 3, 7 % -3);Output
Full vans: 3 Boxes left over: 2 Exact division: 3.4 Area of a 4 m square: 16 Stock: 24 Count: 2 Text plus number: Order 42 Number plus number: 42 Strings times strings: 42 -1 1
/ gives 3.4, so the whole-van count needs Math.floor, and % supplies the two boxes that do not fill a van. stock goes 10, 13, 12, 24 through the compound assignments. With +, one string operand turns the whole thing into text ("Order 42"), whereas * converts both strings to numbers and multiplies. The final line shows that the sign of a remainder follows the left operand.
Comparison: === versus == and how strings compare
The input line is 7, which arrives as a string. Each line prints one comparison.
const typed = readline();
console.log(typed == 7);
console.log(typed === 7);
console.log(Number(typed) === 7);
console.log(0 == "");
console.log(null == undefined);
console.log(null === undefined);
console.log("apple" < "banana");
console.log("Zebra" < "apple");
console.log("10" < "9");
console.log(10 < 9);
console.log(NaN === NaN);Input given to the program: 7
Output
true false true true true false true true true false false
typed is the string "7". Loose equality converts it to a number and says true; strict equality sees a string and a number and says false; converting first and then using === is the honest version. 0 == "" and null == undefined are two of the conversions that make == hard to predict. String comparison works character by character: "Zebra" sorts before "apple" because uppercase Z has a lower code unit than lowercase a, and "10" sorts before "9" because the comparison stops at the first characters, 1 and 9. Convert to numbers before comparing numeric input.
Logical operators, short-circuiting and the ternary
Note which operand || and ?? hand back, and that the two short-circuit lines print nothing.
const age = 16;
const hasPass = true;
console.log(age >= 18 && hasPass);
console.log(age >= 18 || hasPass);
console.log(!hasPass);
console.log("" || "fallback name");
console.log("Ada" || "fallback name");
console.log(0 || 100);
console.log(0 ?? 100);
console.log(null ?? "no value");
false && console.log("never printed");
true || console.log("never printed either");
const label = age >= 18 ? "adult" : "minor";
console.log(label);Output
false true false fallback name Ada 100 0 no value minor
|| returns the first truthy operand, so it works as a default: an empty name becomes the fallback, a real name is kept. The difference between 0 || 100 and 0 ?? 100 is the point of ??: zero is falsy, so || replaces it, but ?? only replaces null or undefined, so a genuine zero survives. The two lines without a console.log on the left never evaluate their right side, which is why nothing is printed for them. The ternary picks one of two strings and stores it.
Common mistakes
Comparing with == and getting surprising matches
Why it goes wrong:
==converts before comparing, so0 == "","1" == 1and[] == falseare all true. Code that works today on one input can misbehave on another.Fix: Use
===and!==, and convert values yourself where a conversion is genuinely wanted.JavaScript · fixconst answer = readline(); if (Number(answer) === 42) { console.log("correct"); }Adding two input values and getting them glued together
Why it goes wrong:
readline()returns strings, and+joins strings:"3" + "4"is"34", not 7.Fix: Convert each operand with
Number()before adding.JavaScript · fixconst a = Number(readline()); const b = Number(readline()); console.log(a + b);Writing = instead of === inside a condition
Why it goes wrong:
if (level = 5)assigns 5 toleveland then tests 5, which is truthy, so the block always runs and the variable is silently changed.Fix: Use
===for comparison. Reading the condition aloud as "is equal to" helps catch the single=.Mixing + on text and numbers without parentheses
Why it goes wrong:
"Total: " + 2 + 3evaluates left to right: the string absorbs the 2, giving"Total: 2", then absorbs the 3, giving"Total: 23".Fix: Group the arithmetic:
"Total: " + (2 + 3), or pass the pieces to console.log as separate arguments.JavaScript · fixconsole.log("Total: " + (2 + 3)); // Total: 5
Where you use this
Price and quantity calculations are the everyday home of these operators: a subtotal from *, a discount chosen with the ternary, % to find what does not fit into a whole number of boxes, minutes or pages, and Math.floor for the whole part. The difference between "3" + "4" and 3 + 4 is the first bug most people meet. The nullish operator earns its place when a value may legitimately be zero, such as a discount or a starting balance, and only a missing value should trigger the default.
const price = Number(readline());
const qty = Number(readline());
const subtotal = price * qty;
const discount = qty >= 10 ? 0.1 : 0;
console.log((subtotal * (1 - discount)).toFixed(2));Key points
+joins strings when either operand is text;-,*,/and%convert text to numbers./gives decimals; useMath.floor()for whole-number division and%for the remainder.- Use
===and!==;==converts types first and is hard to predict. - Strings compare by code unit, so uppercase sorts first and
"10" < "9". ||and&&return an operand and short-circuit;??only replacesnullandundefined.condition ? a : bpicks a value; parentheses make precedence explicit.
Try it yourself
Read a number of minutes and print it as hours and remaining minutes in the form 2 h 15 min, using Math.floor and the % operator.
const minutes = Number(readline());
// compute hours and the remaining minutes, then print them
1352 h 15 minconst minutes = Number(readline());
const hours = Math.floor(minutes / 60);
const rest = minutes % 60;
console.log(hours + " h " + rest + " min");
Practise this
Open the JavaScript playground
Related lessons
- JavaScript Data Types: Primitives, Objects and typeofThe seven primitive types in JavaScript plus objects, what typeof reports, how numbers behave, and how to convert between strings, numbers and booleans.9 min
- Conditions in JavaScript: if, else if, else and switchHow if, else if, else and switch choose what runs in JavaScript, which values count as true, and how to write conditions that do what you meant.8 min
- Variables in JavaScript: let, const and varHow to declare variables in JavaScript with let, const and var, what block scope and hoisting mean, and why const is the default choice.8 min
Frequently asked questions
What is the difference between == and === in JavaScript?
=== compares without converting: the values are equal only if they have the same type and the same content. == first converts both sides to a common type (string to number, boolean to number, null equals undefined) and then compares, which produces results such as 0 == "" being true. Almost all modern code uses === and converts values explicitly when a conversion is intended.
What does ?? do in JavaScript?
a ?? b returns a unless a is null or undefined, in which case it returns b. It differs from a || b, which also replaces any other falsy value such as 0, an empty string or false. Use ?? to supply a default only for missing values. It was added in ES2020 and is supported by Node.js 14 and later and by all current browsers.
Why does "3" + 4 give "34" but "3" * 4 give 12?
The + operator has two jobs, addition and string concatenation, and it picks concatenation as soon as one operand is a string, converting the other to text. The other arithmetic operators have only one job, so they convert both operands to numbers. Convert input with Number() before adding to get arithmetic every time.
How this page was checked. Every program on it was run with Node.js 22 at build time; runs in your browser in an isolated Web Worker by the publishing checks, and the output shown is what it printed. The Run buttons execute the same code on your device; nothing you type is sent anywhere.