Operators & Expressions in JavaScript

Operators are symbols that perform operations on operands (values and variables). Expressions are combinations of values, variables, and operators that evaluate to a value. Understanding operators and expressions is fundamental to writing effective JavaScript code.

Arithmetic Operators

Arithmetic operators perform mathematical operations on numeric values.

// Basic arithmetic operators
let a = 10;
let b = 3;

// Addition (+)
let sum = a + b; // 13

// Subtraction (-)
let difference = a - b; // 7

// Multiplication (*)
let product = a * b; // 30

// Division (/)
let quotient = a / b; // 3.3333...

// Modulus (%) - returns the division remainder
let remainder = a % b; // 1

// Exponentiation (**) - ES2016 (ES7)
let power = a ** b; // 10^3 = 1000

// Increment (++)
let c = 5;
c++; // Post-increment: returns c first, then adds 1
console.log(c); // 6

let d = 5;
++d; // Pre-increment: adds 1 first, then returns d
console.log(d); // 6

// Decrement (--)
let e = 5;
e--; // Post-decrement: returns e first, then subtracts 1
console.log(e); // 4

let f = 5;
--f; // Pre-decrement: subtracts 1 first, then returns f
console.log(f); // 4

Assignment Operators

Assignment operators assign values to JavaScript variables. They combine an arithmetic operation with assignment.

// Basic assignment (=)
let x = 10;

// Addition assignment (+=)
x += 5; // Equivalent to: x = x + 5; (x is now 15)

// Subtraction assignment (-=)
x -= 3; // Equivalent to: x = x - 3; (x is now 12)

// Multiplication assignment (*=)
x *= 2; // Equivalent to: x = x * 2; (x is now 24)

// Division assignment (/=)
x /= 4; // Equivalent to: x = x / 4; (x is now 6)

// Modulus assignment (%=)
x %= 4; // Equivalent to: x = x % 4; (x is now 2)

// Exponentiation assignment (**=)
x **= 3; // Equivalent to: x = x ** 3; (x is now 8)

// Bitwise assignment operators
let y = 5; // Binary: 101
y &= 3; // Binary: y = 5 & 3 = 101 & 011 = 001 (y is now 1)
y |= 6; // Binary: y = 1 | 6 = 001 | 110 = 111 (y is now 7)
y ^= 3; // Binary: y = 7 ^ 3 = 111 ^ 011 = 100 (y is now 4)
y <<= 1; // Binary: y = 4 << 1 = 100 << 1 = 1000 (y is now 8)
y >>= 2; // Binary: y = 8 >> 2 = 1000 >> 2 = 10 (y is now 2)
y >>>= 1; // Binary: y = 2 >>> 1 = 10 >>> 1 = 1 (y is now 1)

Comparison Operators

Comparison operators compare values and return a boolean result (true or false).

let a = 5;
let b = 10;
let c = "5";

// Equal to (==) - compares values, performs type conversion
console.log(a == c); // true (5 == "5" after type conversion)

// Strict equal to (===) - compares both value and type
console.log(a === c); // false (number !== string)

// Not equal to (!=) - compares values, performs type conversion
console.log(a != b); // true (5 != 10)

// Strict not equal to (!==) - compares both value and type
console.log(a !== c); // true (number !== string)

// Greater than (>)
console.log(b > a); // true (10 > 5)

// Less than (<)
console.log(a < b); // true (5 < 10)

// Greater than or equal to (>=)
console.log(a >= 5); // true (5 >= 5)

// Less than or equal to (<=)
console.log(b <= 5); // false (10 <= 5)

// Ternary operator (condition ? expr1 : expr2)
let age = 20;
let status = age >= 18 ? "Adult" : "Minor";
console.log(status); // "Adult"

Logical Operators

Logical operators perform logical operations and return a boolean result.

let x = true;
let y = false;

// Logical AND (&&) - returns true if both operands are true
console.log(x && y); // false

// Logical OR (||) - returns true if at least one operand is true
console.log(x || y); // true

// Logical NOT (!) - reverses the boolean value
console.log(!x); // false

// Short-circuit evaluation
// With &&, if the first operand is false, the second is not evaluated
let a = false && someUndefinedFunction(); // someUndefinedFunction() is never called

// With ||, if the first operand is true, the second is not evaluated
let b = true || someUndefinedFunction(); // someUndefinedFunction() is never called

// Nullish coalescing operator (??) - ES2020
// Returns the right-hand operand when the left is null or undefined
let name = null;
let username = name ?? "Guest";
console.log(username); // "Guest"

// Optional chaining operator (?.) - ES2020
// Allows reading properties from nested objects without checking if each reference is valid
let user = {};
let city = user?.address?.city;
console.log(city); // undefined (no error thrown)

Bitwise Operators

Bitwise operators perform operations on binary representations of numbers.

let a = 5; // Binary: 101
let b = 3; // Binary: 011

// Bitwise AND (&)
console.log(a & b); // 1 (Binary: 101 & 011 = 001)

// Bitwise OR (|)
console.log(a | b); // 7 (Binary: 101 | 011 = 111)

// Bitwise XOR (^)
console.log(a ^ b); // 6 (Binary: 101 ^ 011 = 110)

// Bitwise NOT (~)
console.log(~a); // -6 (Binary: ~00000000000000000000000000000101 = 11111111111111111111111111111010)

// Left shift (<<)
console.log(a << 1); // 10 (Binary: 101 << 1 = 1010)

// Right shift (>>)
console.log(a >> 1); // 2 (Binary: 101 >> 1 = 10)

// Zero-fill right shift (>>>)
console.log(-5 >>> 1); // 2147483645 (Shifts and fills with zeros from the left)

String Operators

JavaScript also provides operators for working with strings.

// Concatenation operator (+)
let firstName = "John";
let lastName = "Doe";
let fullName = firstName + " " + lastName; // "John Doe"

// Concatenation assignment operator (+=)
let greeting = "Hello, ";
greeting += fullName; // "Hello, John Doe"

// Template literals (ES6+)
let message = `${greeting}! Welcome to our website.`;
console.log(message); // "Hello, John Doe! Welcome to our website."

// String comparison
console.log("apple" < "banana"); // true (lexicographical comparison)
console.log("10" > "2"); // false (string comparison, not numeric)

Special Operators

JavaScript has several special operators for specific purposes.

// typeof operator - returns the type of a variable or expression
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (this is a known JavaScript quirk)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function(){}); // "function"

// instanceof operator - tests if an object is an instance of a specific class/constructor
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true (arrays inherit from Object)
console.log(arr instanceof String); // false

// delete operator - deletes an object's property or an array element
let person = { name: "John", age: 30 };
delete person.age;
console.log(person); // { name: "John" }

// void operator - evaluates an expression and returns undefined
console.log(void 0); // undefined
console.log(void(2 + 3)); // undefined

// comma operator (,) - evaluates multiple expressions and returns the last one
let x = (1, 2, 3, 4, 5);
console.log(x); // 5

// The in operator - checks if a property exists in an object
console.log("name" in person); // true
console.log("age" in person); // false (we deleted it)

Operator Precedence

Operator precedence determines the order in which operators are evaluated in an expression.

// Precedence example
let result = 2 + 3 * 4; // 14, not 20 (multiplication has higher precedence)

// Using parentheses to control precedence
let result2 = (2 + 3) * 4; // 20

// Complex example
let x = 5;
let y = 10;
let z = 15;
let complex = x + y * z / 2 - 3; // 5 + (10 * 15) / 2 - 3 = 5 + 150 / 2 - 3 = 5 + 75 - 3 = 77

// Precedence order (from highest to lowest, simplified):
// 1. Grouping: ()
// 2. Member access: . []
// 3. Function call: ()
// 4. Postfix increment/decrement: x++ x--
// 5. Prefix increment/decrement, unary operators: ++x --x +x -x ~ ! typeof void delete
// 6. Exponentiation: **
// 7. Multiplication, division, modulus: * / %
// 8. Addition, subtraction: + -
// 9. Bitwise shift: << >> >>>
// 10. Relational: < <= > >= instanceof in
// 11. Equality: == != === !==
// 12. Bitwise AND: &
// 13. Bitwise XOR: ^
// 14. Bitwise OR: |
// 15. Logical AND: &&
// 16. Logical OR: ||
// 17. Nullish coalescing: ??
// 18. Conditional (ternary): ? :
// 19. Assignment: = += -= *= etc.
// 20. Comma: ,

Expressions in JavaScript

An expression is any valid unit of code that resolves to a value. There are several types of expressions in JavaScript.

// 1. Arithmetic expressions
let sum = 10 + 5; // 15

// 2. String expressions
let greeting = "Hello" + " " + "World"; // "Hello World"

// 3. Logical expressions
let isAdult = age >= 18; // true or false

// 4. Primary expressions
// - Literals
42; // Number literal
"hello"; // String literal
true; // Boolean literal
null; // null literal
/pattern/; // Regular expression literal
[1, 2, 3]; // Array literal
{a: 1, b: 2}; // Object literal

// - this keyword
function demo() {
console.log(this); // refers to the current object
}

// 5. Left-hand-side expressions
// - Property accessors
let person = { name: "John" };
person.name; // dot notation
person["name"]; // bracket notation

// - new operator
let date = new Date();

// - function call
Math.max(1, 2, 3);

// 6. Assignment expressions
let x = 5;

// 7. Conditional expressions
let status = age >= 18 ? "Adult" : "Minor";

// 8. Function expressions
let greet = function(name) {
return `Hello, ${name}!`;
};

// 9. Arrow function expressions (ES6+)
let multiply = (a, b) => a * b;

// 10. Destructuring assignment (ES6+)
let [first, second] = [1, 2];
let { name, age } = { name: "John", age: 30 };

Best Practices for Operators & Expressions

  • Use === and !== instead of == and != to avoid unexpected type conversions
  • Use parentheses to make complex expressions more readable and to ensure correct precedence
  • Be careful with increment/decrement operators in expressions (prefer separate statements)
  • Avoid using the comma operator except in for loops
  • Use template literals for string concatenation when possible
  • Be aware of short-circuit evaluation with && and ||
  • Use the nullish coalescing operator (??) instead of || when you want to distinguish between null/undefined and falsy values

Common Pitfalls and Gotchas

There are several common mistakes and unexpected behaviors when working with JavaScript operators.

// 1. Type coercion with equality operators
console.log(0 == false); // true
console.log(0 === false); // false
console.log('' == false); // true
console.log('' === false); // false

// 2. Addition vs. concatenation
console.log(1 + 2); // 3 (addition)
console.log('1' + 2); // '12' (concatenation)
console.log(1 + '2'); // '12' (concatenation)
console.log(1 + 2 + '3'); // '33' (addition then concatenation)
console.log('1' + 2 + 3); // '123' (concatenation)

// 3. Increment/decrement in expressions
let x = 5;
let y = x++; // y = 5, x = 6

let a = 5;
let b = ++a; // b = 6, a = 6

// 4. Floating-point precision issues
console.log(0.1 + 0.2); // 0.30000000000000004, not exactly 0.3
console.log(0.1 + 0.2 === 0.3); // false

// 5. Logical operators with non-boolean values
console.log('hello' && 'world'); // 'world' (returns the last truthy value)
console.log('' || 'default'); // 'default' (returns the first truthy value)
console.log(null ?? 'default'); // 'default' (nullish coalescing)
console.log('' ?? 'default'); // '' (empty string is not nullish)

// 6. Automatic semicolon insertion
function returnObject() {
return // semicolon automatically inserted here!
{
value: 42
}
} // returns undefined, not the object

// 7. NaN behavior
console.log(NaN === NaN); // false
console.log(Number.isNaN(NaN)); // true (correct way to check)

// 8. Unary plus for type conversion
console.log(+'42'); // 42 (converts string to number)
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+undefined); // NaN

Practice Exercise

Create a JavaScript file that demonstrates the use of different operators. Try to solve these challenges:

  1. Write a function that calculates the area and perimeter of a rectangle using arithmetic operators
  2. Create a function that converts temperatures between Celsius and Fahrenheit
  3. Write a function that checks if a year is a leap year using logical operators
  4. Create a function that determines the grade (A, B, C, D, or F) based on a numeric score using the ternary operator
  5. Write a function that swaps two variables without using a temporary variable

Advanced Topic: Operator Overloading

Unlike some other programming languages, JavaScript does not support operator overloading directly. However, there are some workarounds:

  • For objects, you can implement methods like valueOf() and toString() to control how objects behave with operators
  • The + operator can work with strings (concatenation) or numbers (addition) depending on the operand types
  • The [Symbol.toPrimitive] method (ES6+) gives more control over type conversion in different contexts

Example:

class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}

// Used for addition with +
valueOf() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}

// Used for string concatenation
toString() {
return `(${this.x}, ${this.y})`;
}

// More control over conversion
[Symbol.toPrimitive](hint) {
if (hint === 'number') {
return this.valueOf();
}
if (hint === 'string') {
return this.toString();
}
return this.valueOf();
}
}