Operators are special symbols that perform operations on operands (values and variables). Expressions are combinations of values, variables, operators, and function calls that evaluate to a single value. Understanding operators and expressions is fundamental to programming in JavaScript, as they form the building blocks of data manipulation and program logic.
Operators are symbols or keywords that tell JavaScript to perform specific actions. They can manipulate values, compare values, assign values, or control program flow. Operators work with operands, which are the values or variables that operators act upon.
JavaScript operators can be categorized by the number of operands they work with:
An expression is any valid unit of code that resolves to a value. Expressions can be simple (a single value) or complex (multiple operators and operands). JavaScript evaluates expressions from left to right, following operator precedence rules.
Arithmetic operators perform mathematical calculations on numeric values. These are the most commonly used operators for numerical computations.
The addition operator performs mathematical addition when both operands are numbers, but it also serves as string concatenation when at least one operand is a string.
let sum = 5 + 3; // 8
let text = "Hello" + " World"; // "Hello World"
let mixed = 5 + "5"; // "55" (string concatenation)
The subtraction operator performs mathematical subtraction and always attempts to convert operands to numbers.
let difference = 10 - 3; // 7
let result = "10" - 3; // 7 (string converted to number)
The multiplication operator performs mathematical multiplication, converting operands to numbers as needed.
let product = 6 * 7; // 42
let result = "6" * "7"; // 42 (strings converted to numbers)
The division operator performs mathematical division, returning a floating-point result even when dividing integers.
let quotient = 15 / 3; // 5
let result = 10 / 4; // 2.5
let division = "10" / 2; // 5 (string converted to number)
The remainder operator returns the remainder after division of one number by another.
let remainder = 10 % 3; // 1
let result = 15 % 5; // 0
let check = 10 % 2; // 0 (useful for checking even numbers)
The exponentiation operator raises the first operand to the power of the second operand.
let power = 2 ** 3; // 8 (2 to the power of 3)
let square = 5 ** 2; // 25
let cube = 3 ** 3; // 27
These unary operators modify their operand by adding or subtracting one.
Increments the value and returns the new value.
let count = 5;
let result = ++count; // result is 6, count is 6
Returns the original value, then increments it.
let count = 5;
let result = count++; // result is 5, count is 6
Decrements the value and returns the new value.
let count = 5;
let result = --count; // result is 4, count is 4
Returns the original value, then decrements it.
let count = 5;
let result = count--; // result is 5, count is 4
The assignment operator assigns a value to a variable. The right side is evaluated first, then the result is assigned to the left side.
let x = 10; // x is now 10
let y = x + 5; // y is 15
let a = b = c = 5; // All variables get value 5 (right-to-left)
These operators combine an arithmetic operation with assignment, making code more concise.
Adds the right operand to the left operand and assigns the result.
let num = 10;
num += 5; // num is now 15 (equivalent to num = num + 5)
let text = "Hello";
text += " World"; // text is now "Hello World"
Subtracts the right operand from the left operand and assigns the result.
let num = 15;
num -= 5; // num is now 10 (equivalent to num = num - 5)
Multiplies the left operand by the right operand and assigns the result.
let num = 6;
num *= 3; // num is now 18 (equivalent to num = num * 3)
Divides the left operand by the right operand and assigns the result.
let num = 20;
num /= 4; // num is now 5 (equivalent to num = num / 4)
Calculates the remainder and assigns the result.
let num = 17;
num %= 5; // num is now 2 (equivalent to num = num % 5)
Raises the left operand to the power of the right operand and assigns the result.
let num = 3;
num **= 3; // num is now 27 (equivalent to num = num ** 3)
Comparison operators compare two values and return a boolean result. Understanding the difference between strict and loose equality is crucial for writing predictable code.
Checks if two values are equal without type coercion. Both value and type must be the same.
5 === 5; // true
5 === "5"; // false (different types)
true === 1; // false (different types)
null === undefined; // false (different types)
Checks if two values are not equal without type coercion.
5 !== "5"; // true (different types)
5 !== 5; // false (same value and type)
true !== 1; // true (different types)
Checks if two values are equal with type coercion. JavaScript converts types to make the comparison work.
5 == "5"; // true (string converted to number)
true == 1; // true (boolean converted to number)
false == 0; // true (boolean converted to number)
null == undefined; // true (special case)
"" == 0; // true (string converted to number)
Checks if two values are not equal with type coercion.
5 != "5"; // false (after type coercion, they're equal)
true != 1; // false (after type coercion, they're equal)
These operators compare the relative order of values.
Returns true if the left operand is greater than the right operand.
10 > 5; // true
5 > 10; // false
"10" > 5; // true (string converted to number)
Returns true if the left operand is less than the right operand.
5 < 10; // true
10 < 5; // false
"5" < 10; // true (string converted to number)
Returns true if the left operand is greater than or equal to the right operand.
10 >= 10; // true
10 >= 5; // true
5 >= 10; // false
Returns true if the left operand is less than or equal to the right operand.
5 <= 5; // true
5 <= 10; // true
10 <= 5; // false
When comparing strings, JavaScript uses lexicographical (dictionary) order based on Unicode values.
"apple" < "banana"; // true (a comes before b)
"zebra" > "apple"; // true (z comes after a)
"Apple" < "apple"; // true (uppercase A has lower Unicode value)
The AND operator returns the first falsy value or the last truthy value. It uses short-circuit evaluation.
true && true; // true
true && false; // false
false && true; // false (second operand not evaluated)
false && false; // false
// Short-circuiting examples
let x = 0;
let y = 5;
let result = x && y; // 0 (first falsy value)
// Practical usage for default values
let user = { name: "John" };
let name = user && user.name; // "John"
The OR operator returns the first truthy value or the last falsy value. It also uses short-circuit evaluation.
true || true; // true
true || false; // true (second operand not evaluated)
false || true; // true
false || false; // false
// Short-circuiting examples
let x = 0;
let y = 5;
let result = x || y; // 5 (first truthy value)
// Practical usage for default values
let username = null;
let displayName = username || "Guest"; // "Guest"
The NOT operator converts its operand to a boolean and returns the opposite value.
!true; // false
!false; // true
!0; // true (0 is falsy)
!"hello"; // false (non-empty string is truthy)
!null; // true (null is falsy)
!undefined; // true (undefined is falsy)
// Double NOT for boolean conversion
!!"hello"; // true
!!0; // false
!!null; // false
This operator returns the first operand if it's not null or undefined, otherwise it returns the second operand.
null ?? "default"; // "default"
undefined ?? "default"; // "default"
0 ?? "default"; // 0 (0 is not null/undefined)
"" ?? "default"; // "" (empty string is not null/undefined)
false ?? "default"; // false (false is not null/undefined)
// Comparison with OR operator
let value = 0;
value || "default"; // "default" (0 is falsy)
value ?? "default"; // 0 (0 is not null/undefined)
Converts its operand to a number.
+"5"; // 5
+"hello"; // NaN (Not a Number)
+true; // 1
+false; // 0
+null; // 0
+undefined; // NaN
Negates its operand and converts it to a number.
-5; // -5
-"5"; // -5
-true; // -1
Returns a string indicating the type of the operand.
typeof "hello"; // "string"
typeof 42; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (historical JavaScript bug)
typeof {}; // "object"
typeof []; // "object"
typeof function() {}; // "function"
Deletes a property from an object or an element from an array.
let obj = { name: "John", age: 25 };
delete obj.age; // true (property deleted)
console.log(obj); // { name: "John" }
let arr = [1, 2, 3];
delete arr[1]; // true (element deleted)
console.log(arr); // [1, empty, 3]
console.log(arr.length); // 3 (length doesn't change)
The conditional operator is the only JavaScript operator that takes three operands. It's a concise way to write conditional expressions.
condition ? value_if_true : value_if_false
let age = 18;
let message = age >= 18 ? "Adult" : "Minor"; // "Adult"
While possible, nesting ternary operators can reduce readability.
let score = 85;
let grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" : "F"; // "B"
// Safe property access
let user = { name: "John" };
let city = user.address ? user.address.city : "Unknown"; // "Unknown"
// Conditional assignment
let isLoggedIn = true;
let buttonText = isLoggedIn ? "Logout" : "Login"; // "Logout"
// Function parameter defaults (before ES6)
function greet(name) {
name = name !== undefined ? name : "Guest";
return `Hello, ${name}!`;
}
Operator precedence determines the order in which operations are performed in expressions with multiple operators. Higher precedence operators are evaluated before lower precedence operators.
(). []! ~ + - ++ -- typeof delete void* / %+ -< <= > >= in instanceof== != === !==&&||???:= += -= *= /= %= **=,// Multiplication has higher precedence than addition
let result = 2 + 3 * 4; // 14 (2 + (3 * 4))
// Parentheses override precedence
let result2 = (2 + 3) * 4; // 20 ((2 + 3) * 4)
// Comparison has higher precedence than logical OR
let x = 5 > 3 || 2 > 4; // true ((5 > 3) || (2 > 4))
// Assignment has lowest precedence
let a = b = c = 5; // All become 5 (right-to-left)
Associativity determines the order of evaluation when operators have the same precedence.
// Left-associative (evaluated left to right)
let result = 10 - 5 - 2; // 3 ((10 - 5) - 2)
// Right-associative (evaluated right to left)
let a = b = c = 5; // All become 5 (c = 5, then b = c, then a = b)
Bitwise operators work on 32-bit binary representations of numbers. They're useful for low-level programming and certain optimization techniques.
Performs a bitwise AND operation on each pair of corresponding bits.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a & b; // 1 (Binary: 0001)
Performs a bitwise OR operation on each pair of corresponding bits.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a | b; // 7 (Binary: 0111)
Performs a bitwise exclusive OR operation on each pair of corresponding bits.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a ^ b; // 6 (Binary: 0110)
Performs a bitwise NOT operation, inverting all bits.
let a = 5; // Binary: 0101
let result = ~a; // -6 (Binary: 1010, two's complement)
Shifts bits to the left, filling with zeros on the right.
let a = 5; // Binary: 0101
let result = a << 1; // 10 (Binary: 1010)
Shifts bits to the right, preserving the sign bit.
let a = 5; // Binary: 0101
let result = a >> 1; // 2 (Binary: 0010)
Shifts bits to the right, filling with zeros on the left.
let a = 5; // Binary: 0101
let result = a >>> 1; // 2 (Binary: 0010)
function isEven(num) {
return (num & 1) === 0;
}
let num = 8;
let doubled = num << 1; // 16 (multiply by 2)
let halved = num >> 1; // 4 (divide by 2)
JavaScript automatically converts values between types during operations. This can lead to unexpected results if not understood properly.
When adding a string and a number, the number is converted to a string.
"5" + 3; // "53"
"hello" + 42; // "hello42"
When subtracting, the string is converted to a number.
"10" - 5; // 5
"hello" - 5; // NaN
Booleans are converted to numbers (true = 1, false = 0).
true + 5; // 6
false + 5; // 5
Loose equality (==) performs type coercion, while strict equality (===) does not.
5 == "5"; // true (coerced)
5 === "5"; // false (no coercion)
Always prefer strict equality (===) over loose equality (==) to avoid unexpected type coercion.
// Good
if (value === 5) { }
// Avoid
if (value == 5) { }
When dealing with complex expressions, use parentheses to make the evaluation order clear.
// Clear
let result = (a + b) * (c - d);
// Potentially confusing
let result = a + b * c - d;
Deeply nested ternary operators can be hard to read. Use if-else statements instead.
// Hard to read
let grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F";
// Better
let grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else {
grade = "F";
}
Understand the difference between prefix and postfix operations.
let count = 5;
let result = count++; // result is 5, count becomes 6
let result2 = ++count; // result2 is 7, count is 7
When you want to distinguish between null/undefined and other falsy values, use ?? instead of ||.
// Good for distinguishing 0, "", false from null/undefined
let value = input ?? "default";
// OR treats all falsy values the same
let value2 = input || "default"; // 0, "", false become "default"
function calculate(operation, a, b) {
switch (operation) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return b !== 0 ? a / b : "Cannot divide by zero";
case '%': return a % b;
case '**': return a ** b;
default: return "Invalid operation";
}
}
function validateNumber(input, min = null, max = null) {
const num = Number(input);
if (isNaN(num)) return { valid: false, message: "Not a number" };
if (min !== null && num < min) return { valid: false, message: `Too small (min: ${min})` };
if (max !== null && num > max) return { valid: false, message: `Too large (max: ${max})` };
return { valid: true, value: num };
}
function getGrade(score) {
if (typeof score !== 'number' || score < 0 || score > 100) {
return "Invalid score";
}
return score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" :
score >= 60 ? "D" : "F";
}
Operators and expressions are fundamental building blocks of JavaScript programming. Understanding how different operators work, their precedence, and how JavaScript handles type coercion is essential for writing predictable and efficient code.
Key takeaways:
Mastering operators and expressions provides the foundation for more advanced programming concepts and enables you to write clean, efficient, and maintainable JavaScript code.
Next up: Control Flow - learn how to use conditional statements and loops to control program execution.