Operators: &&
, ||
, delete
, ==
vs ===
, precedence
JavaScript provides a wide variety of operators that perform computations, comparisons, logic, and object manipulation. Understanding these operators — particularly how they behave in non-obvious cases — is critical for writing predictable and readable code.
While some operators like +
and *
are intuitive, others (especially those involving coercion or object mutation) can easily lead to subtle bugs if not clearly understood.
Logical Operators: &&
and ||
&&
(Logical AND)
The &&
operator is primarily used to combine multiple conditions in control flow structures like if
, while
, or ternary expressions:
1if (isLoggedIn && user.role === 'admin') {
2 grantAccess();
3}
It evaluates operands from left to right and returns the first falsy value, or the last value if all are truthy.
1true && 'hello'; // 'hello'
20 && 'world'; // 0
3'text' && 42; // 42
Additional use case: conditional execution
isLoggedIn && showDashboard();
Additional use case: Fallbacks or guards
user && user.profile && user.profile.name;
||
(Logical OR)
Similarly, ||
is often used in conditional checks to cover alternative paths:
1if (user.role === 'admin' || user.role === 'editor') {
2 grantAccess();
3}
It returns the first truthy value, or the last falsy value if none are truthy.
1false || 'fallback'; // 'fallback'
2null || 0 || 'default'; // 'default'
3'hi' || 42; // 'hi'
Additional use case: Default values
const name = inputName || 'Anonymous';
Additional use case: Safe destructuring
const config = options || {};
Short-Circuit Behavior
Both operators short-circuit, meaning:
&&
stops if it finds a falsy value.||
stops if it finds a truthy value.
1function log() {
2 console.log('Called');
3 return true;
4}
5
6false && log(); // log() is not called
7true || log(); // log() is not called
Common Pitfall
These operators return values, not strictly booleans:
const isActive = getUser() && getUser().active; // May return undefined!
For strict boolean logic, use Boolean(...)
or !!
to coerce:
const isActive = !!(getUser() && getUser().active);
Equality Operators: ==
vs ===
JavaScript provides two types of equality operators:
==
(loose equality): compares values after applying type coercion===
(strict equality): compares values without coercion — both value and type must match
===
— Strict Equality (Recommended)
This is the most reliable comparison operator in JavaScript.
11 === 1; // true
21 === '1'; // false
3null === undefined // false
4[] === [] // false (different references)
It compares both type and value, making it predictable and safe for most use cases.
==
— Loose Equality (With Coercion)
The ==
operator converts operands to a common type before comparison, which leads to unintuitive results in many cases.
11 == '1'; // true (string → number)
2false == 0; // true (both falsy)
3null == undefined; // true (special case in spec)
4[] == false; // true (array → '' → 0)
These coercion rules follow complex internal algorithms defined in the ECMAScript specification and are often a source of bugs.
Special Cases to Be Aware Of
1[] == ![] // true
2'' == 0 // true
3false == '0' // true
4NaN == NaN // false
5null == undefined // true
These are rarely what the developer actually intended.
Bonus: Object.is()
There’s a third equality operator: Object.is(a, b), which is like === but with two differences:
1Object.is(+0, -0); // false
2Object.is(NaN, NaN); // true
The delete
Operator
The delete
operator is used to remove a property from an object. It affects only own properties (not inherited ones) and should not be confused with operations like "nulling" or "undefining" a variable.
1const user = { name: 'Alice', age: 30 };
2delete user.age;
3
4console.log(user); // { name: 'Alice' }
Behavior Details
Returns
true
if the property was successfully deleted, or if it didn’t exist.Does not affect variable bindings or array indices directly.
Can break optimizations in JavaScript engines (especially in arrays).
1const obj = {};
2console.log(delete obj.prop); // true
But:
1const x = 5;
2delete x; // false in strict mode
In strict mode, attempting to delete a variable or function will throw an error.
Deleting Array Elements
Using delete
on array elements leaves a hole (i.e., an undefined index), but does not change the array’s length:
1const arr = [1, 2, 3];
2delete arr[1];
3
4console.log(arr); // [1, <1 empty item>, 3]
5console.log(arr.length); // 3
Instead, use .splice()
to remove items cleanly:
arr.splice(1, 1); // removes one element at index 1
Restrictions
Cannot delete variables declared with
let
,const
, orvar
.Cannot delete functions or classes in strict mode.
Can delete dynamic properties of plain objects.
Operator Precedence and Associativity
What is Operator Precedence?
Operator precedence determines the order in which operators are evaluated in complex expressions, especially when parentheses are not used.
For example:
const result = 2 + 3 * 4; // 2 + (3 * 4) = 14
Here, *
has higher precedence than +
, so it’s evaluated first.
What is Associativity?
Associativity defines the direction in which expressions with operators of the same precedence are evaluated:
Left-to-right (left-associative): most arithmetic operators
Copied!10 - 5 - 2; // (10 - 5) - 2 = 3
Right-to-left (right-associative): assignment, exponentiation
Copied!let x = y = z = 5; // x = (y = (z = 5))
Why It Matters
In real-world code, especially in expressions that combine logic and assignment, misunderstanding precedence can lead to subtle bugs:
const result = isValid && isAdmin || isGuest;
Without parentheses, this evaluates as:
const result = (isValid && isAdmin) || isGuest;
But if your intent was:
const result = isValid && (isAdmin || isGuest);
Then you could get the wrong behavior.
Best Practice
Use parentheses to make logic explicit, even when you know the precedence.
Avoid cleverness that depends on associativity unless it’s extremely clear.
Recommended Resources
MDN: Expressions and Operators
JavaScript Info: Operators
ECMAScript Spec – Equality Comparison
MDN: Operator Precedence
2ality Blog: Truthy and Falsy, Coercion, Comparison