JavaScript · Beginner

JavaScript Operators: Arithmetic, Comparison and Logic

9 min readUpdated September 24, 2026Every example verified

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

 JavaScript · 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 operator

Use === and !== unless you have a specific reason to want type conversion. Parentheses cost nothing and make precedence obvious.

== versus ===

Expression=====
5 == "5"truefalse
0 == ""truefalse
0 == falsetruefalse
null == undefinedtruefalse
null == 0falsefalse
"abc" == "abc"truetrue

Arithmetic on a delivery run

Seventeen boxes are loaded five to a van; the later lines show compound assignment, ++ and what + does with text.

 JavaScript
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.

 JavaScript
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.

 JavaScript
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, so 0 == "", "1" == 1 and [] == false are 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 · fix
    const 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 · fix
    const 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 to level and 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 + 3 evaluates 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 · fix
    console.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.

 JavaScript · in practice
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; use Math.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 replaces null and undefined.
  • condition ? a : b picks 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.

Your program
const minutes = Number(readline());
// compute hours and the remaining minutes, then print them
Input the program receives: 135
Expected output: 2 h 15 min

Practise this

Open the JavaScript playground

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.

Progress is stored only in this browser.

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.