◆JavaScript◆Operators◆Beginner◆Beginner to Advanced
Introduction
Operators are symbols that perform operations on operands — values, variables, or expressions. JavaScript provides a comprehensive set of operators spanning arithmetic, comparison, logical, bitwise, assignment, and special-purpose operators. Understanding how each operator works and its precedence in the evaluation order is essential for writing correct expressions.
JavaScript operators can be classified by their arity (unary, binary, ternary) and by their function (arithmetic, comparison, logical, etc.). While most operators are straightforward, JavaScript has several unique behaviors — loose equality coercion, short-circuit evaluation, and the distinction between the nullish coalescing and logical OR operators — that require careful attention.
This page covers every major operator category, the operator precedence table, and the modern operators introduced in ES2020+.
expressions-intro.js
JavaScript
1
// An expression produces a value
2
42;// number literal expression
3
2 + 3; // arithmetic expression
4
a > b ? a : b; // ternary expression
5
x && y; // logical expression
6
7
// Operators combine expressions
8
const result = (5 + 3) * 2 ** 3 / 4 - 1;
9
console.log(result); // 15
Arithmetic Operators
Arithmetic operators perform mathematical calculations. JavaScript follows standard math rules with some unique behaviors around type coercion and special numeric values.
Operator
Name
Example
Result
+
Addition
5 + 3
8
-
Subtraction
5 - 3
2
*
Multiplication
5 * 3
15
/
Division
5 / 3
1.666...
%
Remainder (Modulo)
5 % 3
2
**
Exponentiation
2 ** 4
16
++
Increment
let x=1; x++
1 (returns), 2 (after)
--
Decrement
let x=1; x--
1 (returns), 0 (after)
+ (unary)
Unary Plus
+"42"
42
- (unary)
Unary Negation
-"5"
-5
arithmetic.js
JavaScript
1
// Basic arithmetic
2
console.log(10 + 5); // 15
3
console.log(10 - 5); // 5
4
console.log(10 * 5); // 50
5
console.log(10 / 3); // 3.3333333333333335
6
console.log(10 % 3); // 1(remainder)
7
console.log(2 ** 10); // 1024(exponentiation)
8
9
// Remainder % with negatives — result takes sign of dividend
10
console.log(-5 % 3); // -2
11
console.log(5 % -3); // 2
12
13
// Increment/decrement — prefix vs postfix
14
let a = 0;
15
console.log(a++); // 0 (post-increment: returns old value)
16
console.log(a); // 1
17
18
let b = 0;
19
console.log(++b); // 1 (pre-increment: returns new value)
20
console.log(b); // 1
21
22
// Unary plus — converts to number
23
console.log(+"42");// 42
24
console.log(+true); // 1
25
console.log(+null); // 0
26
console.log(+"hello"); // NaN
27
28
// The + operator is overloaded — addition OR concatenation
console.log(1 + 2 + "3"); // "33" (1+2=3, then 3+"3"="33")
33
console.log("1" + 2 + 3); // "123" (left to right)
34
35
// Other arithmetic operators always coerce to numbers
36
console.log("10" - 2); // 8
37
console.log("10" * "2"); // 20
38
console.log("10" / 2); // 5
ℹ
info
The + operator is the only arithmetic operator that does string concatenation. All other arithmetic operators (-, *, /, %, **) coerce both operands to numbers. Use unary + for explicit numeric conversion.
Comparison Operators
Comparison operators compare values and return a boolean. The choice between strict (===, !==) and loose (==, !=) equality is one of the most important decisions in JavaScript programming.
Operator
Name
Example
Result
===
Strict equality
5 === "5"
false
==
Loose equality
5 == "5"
true (coerces)
!==
Strict inequality
5 !== "5"
true
!=
Loose inequality
5 != "5"
false (coerces)
>
Greater than
5 > 3
true
>=
Greater than or equal
5 >= 5
true
<
Less than
3 < 5
true
<=
Less than or equal
4 <= 5
true
comparison.js
JavaScript
1
// Strict equality — compares value AND type (RECOMMENDED)
2
console.log(5 === 5);// true
3
console.log(5 === "5"); // false — different types
4
console.log(0 === false);// false
5
console.log("" === false);// false
6
console.log(null === undefined); // false
7
console.log(5 !== "5"); // true
8
9
// Loose equality — coerces types before comparing (AVOID)
The rule is simple: always use === and !==. The only exception is checking for null and undefined simultaneously — value == null is true for both. But even then, being explicit with value === null || value === undefined is clearer.
Logical Operators & Short-Circuit Evaluation
Logical operators work with boolean values but return the actual value of one of the operands, not necessarily a boolean. They use short-circuit evaluation — the right operand is evaluated only if necessary. This behavior is commonly used for conditional execution and default values.
Operator
Name
Short-Circuits When
Returns
&&
Logical AND
Left is falsy
First falsy value, or last truthy value
||
Logical OR
Left is truthy
First truthy value, or last falsy value
??
Nullish Coalescing
Left is not null/undefined
Left if not null/undefined, else right
!
Logical NOT
N/A (unary)
Always boolean (inverts truthiness)
!!
Double NOT
N/A (unary)
Coerces to boolean (no inversion)
logical.js
JavaScript
1
// Logical AND (&&) — returns first falsy OR last truthy
2
console.log(true && "hello"); // "hello" (both truthy → last value)
// Common pattern: default values (but watch out for falsy!)
18
const count = 0;
19
console.log(count || 10); // 10 — 0 is falsy, so gets default!
20
console.log(count ?? 10); // 0 — only null/undefined trigger default
21
22
// Short-circuit evaluation in action
23
function expensive() {
24
console.log("expensive called");
25
return true;
26
}
27
28
false && expensive(); // expensive() NEVER called — short-circuits
29
true || expensive(); // expensive() NEVER called — short-circuits
30
31
// Chaining logical operators
32
const name = user && user.profile && user.profile.name || "Anonymous";
33
// Better with optional chaining:
34
const name2 = user?.profile?.name ?? "Anonymous";
35
36
// Logical NOT (!) — always returns boolean
37
console.log(!true);// false
38
console.log(!0); // true
39
console.log(!""); // true
40
console.log(!{}); // false (object is truthy)
41
42
// Double NOT (!!) — coerces to boolean
43
console.log(!!1); // true
44
console.log(!!0); // false
45
console.log(!!""); // false
46
console.log(!!"hello");// true
Logical Assignment Operators (ES2021)
logical-assignment.js
JavaScript
1
// Logical assignment — combine logical operators with assignment
2
// ES2021 — supported in all modern environments
3
4
let a = 0;
5
a ||= 10; // a = a || 10 — assigns if a is falsy
6
console.log(a);// 10
7
8
let b = 1;
9
b &&= 10; // b = b && 10 — assigns if a is truthy
10
console.log(b);// 10
11
12
let c = null;
13
c ??= 10; // c = c ?? 10 — assigns if a is null/undefined
14
console.log(c);// 10
15
16
// Practical examples
17
let config = {};
18
config.timeout ??= 3000; // only setif missing
19
config.retries ??= 3;
20
21
let userSettings = {};
22
userSettings.theme ||= "light"; // set default
23
24
let isValid = true;
25
isValid &&= validateForm(); // only validate if already valid
✓
best practice
Understand the difference between || and ??. The || operator treats all falsy values (0, "", false, null, undefined, NaN) as false. The ?? operator only treats null and undefined as false. Use ?? for default values when 0 or "" are valid inputs.
Nullish Coalescing & Optional Chaining
Introduced in ES2020, the nullish coalescing operator (??) and optional chaining operator (?.) together eliminate an entire category of null-checking boilerplate. They are among the most impactful modern JavaScript features.
nullish-optional.js
JavaScript
1
// Nullish coalescing (??) — default only for null/undefined
const city = data && data.user && data.user.address && data.user.address.city;
28
29
// With optional chaining — clean
30
const city2 = data?.user?.address?.city;
31
console.log(city2); // undefined — no error
32
33
// Optional method call
34
const result = obj?.method?.();
35
console.log(data?.nonexistent?.());// undefined
36
37
// Optional dynamic property access
38
const key = "address";
39
console.log(data?.user?.[key]?.city);
40
41
// Optional chaining with delete
42
delete data?.user?.address;
43
44
// Short-circuiting — stops at first null/undefined
45
data?.user?.profile?.name?.toUpperCase();
46
// If data, user, profile, or name is null/undefined → undefined
🔥
pro tip
Optional chaining and nullish coalescing work together perfectly: data?.user?.name ?? "Anonymous". The first part safely accesses deeply nested properties, and the second provides a fallback if the result is null or undefined. This pattern replaces the vast majority of manual null checks.
Bitwise Operators
Bitwise operators treat operands as 32-bit signed integers and perform operations at the binary level. They are rarely used in everyday JavaScript but are essential for low-level programming, flags/enums, performance-critical binary operations, and certain algorithms.
Operator
Name
Example
Binary Result
&
AND
5 & 3
1 (0101 & 0011 = 0001)
|
OR
5 | 3
7 (0101 | 0011 = 0111)
^
XOR
5 ^ 3
6 (0101 ^ 0011 = 0110)
~
NOT
~5
-6 (inverts all bits)
<<
Left shift
5 << 1
10 (0101 → 1010)
>>
Sign-propagating right shift
-5 >> 1
-3 (preserves sign)
>>>
Zero-fill right shift
-5 >>> 1
2147483645 (unsigned)
bitwise.js
JavaScript
1
// Bitwise AND, OR, XOR
2
console.log(5 & 3); // 1 (0101 & 0011 = 0001)
3
console.log(5 | 3); // 7 (0101 | 0011 = 0111)
4
console.log(5 ^ 3); // 6 (0101 ^ 0011 = 0110)
5
console.log(~5); // -6 (inverts all bits)
6
7
// Bitwise shifts
8
console.log(5 << 1);// 10 (multiply by 2)
9
console.log(5 << 2);// 20 (multiply by 4)
10
console.log(16 >> 1); // 8(divide by 2)
11
console.log(16 >> 2); // 4(divide by 4)
12
console.log(-16 >> 1); // -8(sign-preserving)
13
14
// Practical: flag/enum pattern
15
const PERMISSION_READ = 1; // 001
16
const PERMISSION_WRITE = 2; // 010
17
const PERMISSION_EXEC = 4; // 100
18
19
let permissions = PERMISSION_READ | PERMISSION_WRITE; // 011
// in — checks if property exists in object (including prototype)
47
console.log("toString" in{}); // true (inherited)
48
console.log("a" in{a:1}); // true
49
console.log("b" in{a:1}); // false
50
51
// in with arrays — checks index, not value
52
const arr = [10, 20, 30];
53
console.log(0 in arr); // true (index 0 exists)
54
console.log(3 in arr); // false (index 3 doesn't exist)
55
console.log("length" in arr);// true
Comma Operator
The comma operator evaluates each of its operands left to right and returns the value of the last operand. It is rarely necessary but occasionally useful in specific patterns.
comma-operator.js
JavaScript
1
// Comma operator — evaluates both, returns last
2
const result = (1, 2,3);
3
console.log(result); // 3
4
5
// Side effects with comma
6
let a = 0, b = 0;
7
const val = (a++, b++, a + b);
8
console.log(val); // 2 (a=1, b=1, 1+1=2)
9
10
// Practical: for loop with multiple counters
11
for (let i = 0, j = 10; i < j; i++, j--) {
12
console.log(i, j);
13
}
14
15
// Practical: arrow function with side effects
16
const getNextId = (() => {
17
let id = 0;
18
return () => (id++, id);
19
})();
20
console.log(getNextId());// 1
21
console.log(getNextId());// 2
22
23
// Comma in ternary (use sparingly — often hurts readability)
// Without parens: same result but harder to parse
Operator Precedence
Operator precedence determines the order in which operators are evaluated in expressions. Operators with higher precedence are evaluated first. When operators have the same precedence, associativity (left-to-right or right-to-left) determines the evaluation order.
Precedence
Operator
Associativity
19
() Grouping
n/a
18
.[]?.()
left-to-right
17
new (with args) .
n/a
16
!~+-typeofvoiddelete
right-to-left
15
**
right-to-left
14
*/%
left-to-right
13
+-
left-to-right
12
<<>>>>>
left-to-right
11
<<=>>=ininstanceof
left-to-right
10
==!====!==
left-to-right
9
&
left-to-right
8
^
left-to-right
7
|
left-to-right
6
&&
left-to-right
5
||
left-to-right
4
??
right-to-left
3
? : (ternary)
right-to-left
2
=+=-=**=||=??= etc.
right-to-left
1
, (comma)
left-to-right
precedence.js
JavaScript
1
// Understanding precedence with real examples
2
console.log(2 + 3 * 4); // 14 (* has higher precedence than +)
You do not need to memorize the precedence table. When in doubt, use parentheses (). They cost nothing in readability and ensure your intent is clear. Complex expressions without parentheses are a maintenance burden — your future self and colleagues will thank you.
Assignment Operators
assignment.js
JavaScript
1
// Basic assignment
2
let x = 10;
3
4
// Compound assignment — applies operator then assigns
5
x += 5; // x = x + 5 → 15
6
x -= 3; // x = x - 3 → 12
7
x *= 2; // x = x * 2 → 24
8
x /= 4; // x = x / 4 → 6
9
x %= 2; // x = x % 2 → 0
10
x **= 3; // x = x ** 3 → 0 (0**3 = 0)
11
x = 5;
12
x <<= 1; // x = x << 1 → 10
13
x >>= 1; // x = x >> 1 → 5
14
x >>>= 1; // x = x >>> 1 → 2
15
x &= 3; // x = x & 3 → 1
16
x |= 2; // x = x | 2 → 3
17
x ^= 1; // x = x ^ 1 → 2
18
19
// Logical assignment (ES2021)
20
let a = null;
21
a ??= "default"; // assigns only if null/undefined
22
23
let b = 0;
24
b ||= 10; // assigns only if falsy
25
26
let c = true;
27
c &&= "set"; // assigns only if truthy
28
29
// Destructuring assignment
30
const [first, second] = [10, 20];
31
const { name, age } = { name: "Alice", age: 30};
Operator Best Practices
◆Always use === and !== — never use == or != which coerce types silently
◆Use ?? for default values instead of || when 0 or empty string are valid values
◆Use optional chaining ?. for safe deep property access — replace nested && checks
◆Use parentheses to clarify complex expressions — readability over cleverness
◆Avoid nested ternaries — they are hard to read. Use if/else or switch instead
◆Use unary + for explicit numeric conversion — it's concise and clear
◆Understand short-circuit evaluation — && runs the right side only if left is truthy
◆Prefer logical assignment (||=, &&=, ??=) for cleaner conditional assignment
◆Avoid the comma operator in most code — it usually hurts readability
◆Use ~~ only when you specifically need 32-bit integer truncation, not Math.floor()
🔥
pro tip
The most common operator mistake in JavaScript: using = instead of === in conditions (e.g., if (x = 5) instead of if (x === 5)). Use a linter (ESLint with no-cond-assign) to catch this automatically. This one rule prevents more bugs than almost any other.