JavaScript Operators

Beginner 6 min read

Operators are symbols that perform operations on values. JavaScript has arithmetic, comparison, logical, and assignment operators, plus modern ones like nullish coalescing.

Arithmetic Operators

Perform mathematical calculations on numbers:

javascript
// Basic arithmetic
let a = 10, b = 3;

a + b   // 13 (addition)
a - b   // 7 (subtraction)
a * b   // 30 (multiplication)
a / b   // 3.333... (division)
a % b   // 1 (modulo/remainder)
a ** b  // 1000 (exponentiation, 10^3)

// Increment and decrement
let count = 5;
count++  // 6 (post-increment)
++count  // 7 (pre-increment)
count--  // 6 (post-decrement)
--count  // 5 (pre-decrement)

// String concatenation with +
"Hello" + " " + "World"  // "Hello World"
"Age: " + 25             // "Age: 25"
String Concatenation
The + operator also concatenates strings. If one operand is a string, the other is converted: "5" + 3 gives "53".

Comparison Operators

Compare values and return a boolean:

javascript
// Equality operators
5 == "5"    // true (loose, converts types)
5 === "5"   // false (strict, different types)
5 != "5"    // false
5 !== "5"   // true

// Relational operators
5 > 3       // true
5 >= 5      // true
5 < 3       // false
5 <= 5      // true

// Comparing strings (alphabetically)
"apple" < "banana"  // true
"A" < "a"           // true (uppercase before lowercase)

// Comparing with null/undefined
null == undefined   // true
null === undefined  // false

== vs === (The Golden Rule)

Expression== (loose)=== (strict)
5 and "5"
0 and false
0 and ""
null and undefined
[] and false
"" and false
Always Use ===
The loose equality operator (==) performs type coercion which leads to surprising results. Always use strict equality (===) to compare both value and type.

Logical Operators

Combine or invert boolean values:

javascript
// AND (&&) - all must be true
true && true    // true
true && false   // false
false && true   // false

// OR (||) - at least one must be true
true || false   // true
false || true   // true
false || false  // false

// NOT (!) - inverts the value
!true   // false
!false  // true
!!0     // false (double negation converts to boolean)
!!"hi"  // true

// Short-circuit evaluation
const user = null;
const name = user && user.name;  // null (stops at falsy)
const defaultName = name || "Guest";  // "Guest"
Short-Circuit Evaluation
&& stops at the first falsy value. || stops at the first truthy value. This is useful for defaults and conditional execution.

Assignment Operators

Assign values to variables, with optional operations:

javascript
let x = 10;

x += 5;   // x = x + 5 (15)
x -= 3;   // x = x - 3 (12)
x *= 2;   // x = x * 2 (24)
x /= 4;   // x = x / 4 (6)
x %= 4;   // x = x % 4 (2)
x **= 3;  // x = x ** 3 (8)

// Logical assignment (ES2021)
let a = null;
a ??= "default";  // a = a ?? "default" ("default")

let b = 0;
b ||= 10;  // b = b || 10 (10, because 0 is falsy)

let c = 5;
c &&= 10;  // c = c && 10 (10, because 5 is truthy)

Ternary Operator

A shorthand for simple if-else statements:

javascript
// Ternary operator: condition ? ifTrue : ifFalse
const age = 20;
const status = age >= 18 ? "adult" : "minor";
console.log(status);  // "adult"

// Equivalent if-else
let status2;
if (age >= 18) {
  status2 = "adult";
} else {
  status2 = "minor";
}

// Nested ternary (use sparingly!)
const score = 85;
const grade = score >= 90 ? "A"
            : score >= 80 ? "B"
            : score >= 70 ? "C"
            : "F";
console.log(grade);  // "B"
Avoid Nesting
Nested ternary operators quickly become unreadable. Use if-else statements for complex conditions.

Nullish Coalescing & Optional Chaining

Modern operators for handling null/undefined values safely:

javascript
// Nullish coalescing (??)
// Returns right side ONLY for null/undefined

const value1 = null ?? "default";     // "default"
const value2 = undefined ?? "default"; // "default"
const value3 = 0 ?? "default";        // 0 (not nullish!)
const value4 = "" ?? "default";       // "" (not nullish!)
const value5 = false ?? "default";    // false (not nullish!)

// Compare with ||
const a = 0 || "default";   // "default" (0 is falsy)
const b = 0 ?? "default";   // 0 (0 is not nullish)

// Optional chaining (?.)
const user = { name: "Alice" };
user?.name      // "Alice"
user?.address   // undefined (no error)
user?.address?.city  // undefined (no error)

// Combined with nullish coalescing
const city = user?.address?.city ?? "Unknown";  // "Unknown"
?? vs ||
Use ?? when 0, "", or false are valid values. Use || only when you want to replace all falsy values.

Try It Yourself

Experiment with different operators:

index.js
// Arithmetic Operators
console.log("=== Arithmetic ===");
console.log("5 + 3 =", 5 + 3);   // 8
console.log("5 - 3 =", 5 - 3);   // 2
console.log("5 * 3 =", 5 * 3);   // 15
console.log("5 / 3 =", 5 / 3);   // 1.666...
console.log("5 % 3 =", 5 % 3);   // 2 (remainder)
console.log("5 ** 3 =", 5 ** 3); // 125 (exponent)

// Comparison Operators
console.log("\n=== Comparison ===");
console.log("5 == '5':", 5 == '5');   // true (loose)
console.log("5 === '5':", 5 === '5'); // false (strict)
console.log("5 > 3:", 5 > 3);         // true
console.log("5 >= 5:", 5 >= 5);       // true
console.log("5 != '5':", 5 != '5');   // false
console.log("5 !== '5':", 5 !== '5'); // true

// Logical Operators
console.log("\n=== Logical ===");
console.log("true && false:", true && false); // false
console.log("true || false:", true || false); // true
console.log("!true:", !true);                 // false

// Assignment Operators
console.log("\n=== Assignment ===");
let x = 10;
x += 5; console.log("x += 5:", x);  // 15
x -= 3; console.log("x -= 3:", x);  // 12
x *= 2; console.log("x *= 2:", x);  // 24
x /= 4; console.log("x /= 4:", x);  // 6

See how short-circuit evaluation and nullish coalescing differ:

index.js
// Short-circuit with ||
console.log("=== OR (||) - returns first truthy ===");
console.log(null || "default");     // "default"
console.log(0 || "default");        // "default" (0 is falsy!)
console.log("" || "default");       // "default" (empty string is falsy!)
console.log("hello" || "default");  // "hello"

// Short-circuit with &&
console.log("\n=== AND (&&) - returns first falsy ===");
console.log(true && "hello");       // "hello"
console.log(false && "hello");      // false
console.log("hi" && "hello");       // "hello"

// Nullish coalescing (??) - only null/undefined
console.log("\n=== Nullish (??) - only null/undefined ===");
console.log(null ?? "default");     // "default"
console.log(undefined ?? "default"); // "default"
console.log(0 ?? "default");        // 0 (0 is NOT nullish!)
console.log("" ?? "default");       // "" (empty string is NOT nullish!)

// Optional chaining (?.)
console.log("\n=== Optional Chaining (?.) ===");
const user = { name: "Alice", address: { city: "NYC" } };
console.log(user?.name);            // "Alice"
console.log(user?.address?.city);   // "NYC"
console.log(user?.phone?.number);   // undefined (no error!)

Best Practices

1. Always Use === and !==
Strict equality prevents type coercion bugs. There's almost never a reason to use ==.
2. Use ?? for Defaults with Valid Falsy Values
When 0, "", or false are valid values, use ?? instead of ||.
3. Use ?. for Safe Property Access
Optional chaining (?.) prevents "Cannot read property of undefined" errors.
4. Avoid Complex Ternary Chains
If you're nesting ternary operators, refactor to if-else or a switch statement.

Test Your Knowledge

Test Your Knowledge

5 questions
Question 1

What does 5 === "5" return?

Question 2

What does null ?? "default" return?

Question 3

What does 0 || "default" return?

Question 4

What does 10 % 3 return?

Question 5

What does true && false || true return?

Practice Exercises

Challenge 1: Safe Division

Easy

Create a function that safely divides two numbers, returning 0 for invalid inputs or division by zero.

Starter Code
// Challenge: Create a function that safely divides two numbers
// Return 0 if dividing by zero, and handle non-number inputs

function safeDivide(a, b) {
  // TODO: Return a / b, but:
  // - Return 0 if b is 0 (avoid division by zero)
  // - Return 0 if either a or b is not a number
  // - Return the result otherwise
}

console.log(safeDivide(10, 2));   // should print 5
console.log(safeDivide(10, 0));   // should print 0
console.log(safeDivide("10", 2)); // should print 0
console.log(safeDivide(10, "2")); // should print 0
console.log(safeDivide(0, 5));    // should print 0

Challenge 2: Config with Defaults

Medium

Create a function that gets config values with defaults, preserving valid falsy values like 0 and false.

Starter Code
// Challenge: Create a function that gets a config value with defaults
// Use nullish coalescing and optional chaining

function getConfig(config, key, defaultValue) {
  // TODO: Return config[key] if it exists and is not null/undefined
  // Otherwise return defaultValue
  // Handle cases where config itself might be null/undefined
}

const config = {
  theme: "dark",
  fontSize: 0,  // 0 is a valid value!
  showTips: false,  // false is a valid value!
  username: null
};

console.log(getConfig(config, "theme", "light"));      // should print "dark"
console.log(getConfig(config, "fontSize", 14));        // should print 0 (not 14!)
console.log(getConfig(config, "showTips", true));      // should print false (not true!)
console.log(getConfig(config, "username", "Guest"));   // should print "Guest"
console.log(getConfig(config, "language", "en"));      // should print "en"
console.log(getConfig(null, "theme", "light"));        // should print "light"

Frequently Asked Questions

What is operator precedence?

Operators have different priorities. Multiplication happens before addition (2 + 3 * 4 = 14, not 20). Use parentheses to make intent clear: (2 + 3) * 4 = 20.

When should I use ++ vs += 1?

Both work, but += 1 is clearer. The difference between x++ and ++x (post vs pre-increment) can cause bugs. Many style guides prefer += 1 for clarity.

Can I chain optional chaining?

Yes! user?.address?.city?.name safely accesses deeply nested properties. If any part is null or undefined, the whole expression returns undefined instead of throwing an error.

What are bitwise operators?

Bitwise operators (&, |, ^, ~, <<, >>) work on binary representations of numbers. They're rarely used in typical JavaScript but are useful for flags and low-level operations.

Summary

JavaScript operators let you manipulate values in different ways:

  • Arithmetic: +, -, *, /, %, ** for math operations
  • Comparison: ===, !==, <, >, <=, >= for comparisons
  • Logical: &&, ||, ! for boolean logic
  • Assignment: =, +=, -=, etc. for assigning values
  • Ternary: condition ? a : b for inline conditionals
  • Nullish: ?? and ?. for safe null/undefined handling

Key takeaways:

  • Always use === instead of ==
  • Use ?? when 0, "", or false are valid values
  • Use ?. to safely access nested properties