JavaScript operators: a practical guide with examples

JavaScript operators: a practical guide with examples
JavaScript operators: a practical guide with examples

Operators in JavaScript turn values into results. They calculate totals, compare data, choose defaults, inspect objects, and decide which code should run. This guide groups the operators you will use most, shows what each expression actually returns, and explains the coercion and precedence rules behind common bugs.

JavaScript operators at a glance

An operator is a symbol or keyword that acts on one or more values, called operands, and forms an expression. In price * quantity, * is the operator, while price and quantity are its operands. The expression produces a value.

Operators can also be grouped by the number of operands they take:

  • Unary: one operand, as in !isReady or typeof value
  • Binary: two operands, as in total + tax or age >= 18
  • Ternary: three operands, using condition ? valueA : valueB

There is no single canonical number of JavaScript operator types. Tutorials group them differently, and some expression syntax looks like an operator even when the language specification classifies it another way. These practical groups cover what you will encounter in everyday code:

GroupCommon operatorsMain job
Arithmetic+, -, *, /, %, **, ++, --Calculate numeric values
Assignment=, +=, -=, *=, /=, &&=, ||=, ??=Store or update a value
Equality and comparison===, !==, ==, !=, <, <=, >, >=Compare values
Logical and defaults&&, ||, !, ??Combine conditions or select a value
Conditional? :Choose between two values
Property and type?., in, instanceof, typeof, delete, new, voidWork with objects and types
Bitwise&, |, ^, ~, <<, >>, >>>Manipulate integer bit patterns

The complete operator reference also covers specialized expression syntax such as await, yield, the comma operator, and grouping.

Arithmetic operators

JavaScript supports the arithmetic operators familiar from mathematics, plus remainder, exponentiation, increment, and decrement.

OperatorMeaningExampleResult
+Addition7 + 310
-Subtraction7 - 34
*Multiplication7 * 321
/Division7 / 23.5
%Remainder7 % 31
**Exponentiation2 ** 416
++Incrementcount++Adds 1 to count
--Decrementcount--Subtracts 1 from count

The + operator has a second job. If either operand becomes a string, it concatenates strings:

2 + 3; // 5 "2" + 3; // "23" 2 + 3 + "4"; // "54"

The last expression runs from left to right. 2 + 3 produces 5, then 5 + "4" produces the string "54". Template literals usually make string construction clearer:

const fullName = `${firstName} ${lastName}`;

Prefix and postfix increment both change a variable. Their expression results differ:

let attempts = 2; const beforeChange = attempts++; // beforeChange is 2, attempts is now 3 const afterChange = ++attempts; // attempts becomes 4, afterChange is 4

Arithmetic works with both number and BigInt values, with some operator-specific limits. Do not mix the two numeric types in one arithmetic expression:

10n + 5n; // 15n 10n + 5; // TypeError

Assignment operators

The assignment operator = stores the right-hand value in the left-hand target. Compound assignments calculate and store in one expression.

let total = 10; total += 5; // 15 total *= 2; // 30 total **= 2; // 900

The same pattern exists for the other arithmetic and bitwise operators. JavaScript also has three logical assignment operators:

let label = ""; let retries = 0; let owner; label ||= "Unknown"; // assigns because "" is falsy retries &&= 1; // does not assign because 0 is falsy owner ??= "Queue"; // assigns because owner is undefined

Logical assignment short-circuits. The assignment happens only when the left value meets that operator's condition. This matters when the right side calls a function or performs other work.

Assignment itself produces the assigned value and associates from right to left, so a = b = 5 sets both variables to 5. Separate assignments are easier to read and debug.

Equality and comparison operators

Comparison operators produce a Boolean value. Strict equality checks type and value. Loose equality may convert operands before comparing them.

5 === 5; // true 5 === "5"; // false 5 == "5"; // true 0 == false; // true 0 === false; // false

Use === and !== by default. They keep implicit conversion out of the comparison. One deliberate use of loose equality is value == null, which is true for both null and undefined. A more explicit equivalent is value === null || value === undefined.

Strict equality has two details worth remembering:

NaN === NaN; // false Object.is(NaN, NaN); // true ({} === {}); // false const contact = {}; contact === contact; // true

Objects compare by identity, not by matching contents. Object.is() handles NaN and signed zero differently from ===, which makes it useful for a few edge cases.

The relational operators <, <=, >, and >= compare order. Two strings are compared as strings. Other combinations can trigger numeric conversion:

"12" < "3"; // true, string comparison 12 < "3"; // false, numeric comparison

Convert input explicitly when its type is uncertain. Number(value) and String(value) make the intended comparison visible.

Logical operators, short-circuiting, and defaults

The logical operators are often introduced with truth tables. In application code, their return values matter just as much. && and || return an operand, rather than always returning true or false.

OperatorEvaluation rule
a && bReturns the first falsy operand, or the last operand if all are truthy
a || bReturns the first truthy operand, or the last operand if all are falsy
!aConverts a to Boolean and reverses it
a ?? bReturns b only when a is null or undefined
"connected" && 200; // 200 0 && getStatus(); // 0, getStatus is not called "" || "Anonymous"; // "Anonymous" 0 || 10; // 10 0 ?? 10; // 0

That last pair explains when to use ??. Choose || when every falsy value should trigger the fallback. Choose ?? when 0, false, and an empty string are valid data.

The right operand of &&, ||, or ?? is evaluated only when needed. This behavior is called short-circuit evaluation. It can avoid an unnecessary function call, though long chains with side effects are hard to follow.

JavaScript requires parentheses when ?? appears directly beside && or ||:

const name = (profile.nickname || profile.firstName) ?? "Caller";

The conditional operator

The conditional operator selects one of two expressions:

const route = waitSeconds < 30 ? "stay-in-queue" : "offer-callback";

It evaluates the condition first, then evaluates only the selected branch. Use it when both branches produce a value and remain readable on one or a few short lines. Use an if...else statement for several actions or deeply nested decisions. Our guide to JavaScript conditionals covers that choice in more detail.

Property and type operators

Several operators answer questions about an object or access its data.

Optional chaining and typeof

Optional chaining ?. stops a property access or call when the value to its left is null or undefined. The expression then returns undefined.

const callerName = session.contact?.profile?.name ?? "Caller"; const onComplete = session.hooks?.onComplete; onComplete?.();

It does not hide every error. If session itself was never declared, session?.contact still throws a ReferenceError.

The typeof operator returns a string describing the operand's type:

typeof 42; // "number" typeof "hello"; // "string" typeof undefined; // "undefined" typeof (() => {}); // "function" typeof null; // "object", a long-standing language behavior typeof []; // "object"

Use Array.isArray(value) to identify arrays. For null, compare the value directly.

in, instanceof, delete, and new

The in operator checks whether a property exists on an object or anywhere in its prototype chain. It checks property names, not array values.

const contact = { phone: "+1 555 0100" }; "phone" in contact; // true Object.hasOwn(contact, "phone"); // true, own property only 0 in ["queued"]; // true, index 0 exists "queued" in ["queued"]; // false

instanceof checks whether a constructor's prototype appears in an object's prototype chain. new creates an object through a constructor. delete removes a configurable own property:

const startedAt = new Date(); startedAt instanceof Date; // true const state = { status: "queued", temporary: true }; delete state.temporary;

Deleting an array element leaves an empty slot and does not shorten the array. Use splice() or filter() when you need to remove array items. You can learn more about those choices in our guide to JavaScript arrays.

The void operator evaluates an expression and returns undefined. It appears in a few specialized patterns, though most application code can state its intent more clearly without it.

Bitwise operators

Bitwise operators work on binary representations. With number operands, JavaScript converts values to 32-bit integers before applying most bitwise operations.

OperatorOperation
&AND
|OR
^XOR
~NOT
<<Left shift
>>Sign-propagating right shift
>>>Zero-fill right shift

Bit flags are one practical use:

const CAN_READ = 1; // 001 const CAN_WRITE = 2; // 010 const CAN_CALL = 4; // 100 const permissions = CAN_READ | CAN_CALL; // 101 const mayCall = Boolean(permissions & CAN_CALL); // true

Most business logic is clearer with named Booleans, sets, or objects. Bitwise code is useful for compact flags, binary protocols, graphics, and low-level algorithms. The BigInt-compatible bitwise operators accept only BigInt operands, and >>> does not support BigInt. Mixing a number and a BigInt throws a TypeError.

Operator precedence and associativity

Precedence decides which operator binds first. Associativity decides how operators at the same precedence level group.

2 + 3 * 4; // 14 (2 + 3) * 4; // 20 2 ** 3 ** 2; // 512, read as 2 ** (3 ** 2)

Multiplication has higher precedence than addition. Exponentiation associates from right to left. Parentheses make a different grouping explicit.

You do not need to memorize the entire operator-precedence table. Learn the common arithmetic order, then add parentheses when an expression combines logical, comparison, conditional, or assignment operators. Parentheses are useful even when the default order already produces the intended result because they show that order to the next reader.

Common JavaScript operator mistakes

Use this checklist when an expression returns a surprising value:

  1. Assignment in a condition: if (status = "ready") assigns a value. A comparison usually needs ===.
  2. Loose equality coercion: == can convert types. Prefer === unless coercion is intentional.
  3. The wrong default operator: || replaces every falsy value. Use ?? when 0, false, or "" should survive.
  4. Assuming logical operators return Booleans: && and || return one of their operands. Wrap the expression in Boolean() when the output must be Boolean.
  5. Comparing object contents with ===: two separately created objects are different references, even if they hold the same fields.
  6. Using typeof for arrays or null: both report "object". Use Array.isArray() and a direct null comparison.
  7. Using in to find an array value: in checks keys. Use includes() to find a value.
  8. Mixing number and BigInt: convert deliberately before arithmetic or bitwise operations.
  9. Relying on remembered precedence: add parentheses around the intended groups.

Is $ a JavaScript operator?

$ is not a built-in JavaScript operator. It is a valid character in an identifier, so a library or application can use $ as a variable or function name. In a template literal, ${expression} marks a value to interpolate into the string.

Other punctuation is also context-dependent. ... introduces spread or rest syntax, and => defines an arrow function. Developers often call them operators informally, though the language grammar treats their roles more specifically.

Put the operators together

Real code usually combines several operators. This function chooses the next step in a voice workflow while preserving valid zero values and handling missing nested data:

function chooseNextAction(session) { const retries = session.retries ?? 0; const isVerified = session.contact?.verification === "verified"; const mayCallback = session.contact?.callbackConsent === true; const canRetry = session.status !== "connected" && retries < 2; if (isVerified && mayCallback) { return "offer-callback"; } return canRetry ? "retry" : "human-handoff"; }

The example uses ?? for a nullish default, ?. for guarded access, strict equality for predictable comparisons, && to require multiple conditions, < to enforce a retry limit, and the conditional operator to select a value.

Open a browser console or Node.js REPL and change one operand at a time. Predict the result before you run each expression. That short feedback loop makes JavaScript's coercion, short-circuiting, and precedence rules easier to predict.

Related Posts

We use cookies for functional and analytical purposes. Please refer to our Privacy Policy for details.