Sitemap
Many Minds

The idea is to learn something for myself and share what I have learned.

Mastering JavaScript Operators: Concepts, Coercion, and Pitfalls

20 min readOct 13, 2026

--

Press enter or click to view image in full size

Every software program works with two important things: data and operations.

To understand how JavaScript operators work, we first need to understand two basic terms: operands and operators.

  • Operands are the values or variables on which an operation is performed.
  • Operators are symbols that perform an action on those values or variables.

For example:

const result = 10 + 5;

In this example:

  • 10 and 5 are the operands because they are the values used in the operation.
  • + is the operator because it adds the two operands.
  • 15 is the result of the operation.

Operators allow us to perform calculations, compare values, and make decisions in our programs.

For example, in an online shopping application, we can calculate the total price of an order and check whether it exceeds the customer’s budget.

const price = 100;
const quantity = 3;
const budget = 250;

const total = price * quantity;

console.log(total); // 300

if (total > budget) {
console.log("The order exceeds the budget.");
}

Here, price and quantity are operands, while * is the multiplication operator. In the condition total > budget, total and budget are operands, while > is the comparison operator.

So, JavaScript operators may look simple, but their behavior can become complicated when different data types are involved. For example, "5" + 3 produces "53", while "5" - 3 produces 2.

Understanding why this happens is essential for writing reliable JavaScript code.

1. Why Do Operators Exist?

Operators allow a program to work with data and make decisions based on that data.

For this blog, I will focus on three important groups of operators:

Arithmetic operators perform calculations and produce values.

const total = price * qty;

Comparison operators compare values and produce a Boolean result, usually true or false.

const isOverBudget = total > budget;

Logical operators combine conditions, select values, or control whether an expression is evaluated.

if (total > budget && qty > 0) {
console.log("Check the order.");
}

Each group serves a different purpose:

Press enter or click to view image in full size

JavaScript also provides assignment, bitwise, and other operators. However, arithmetic, comparison, and logical operators are particularly important when learning how JavaScript evaluates expressions.

2. Why Does JavaScript Perform Type Coercion?

JavaScript was introduced in 1995 and was designed for interactive web applications. Web applications frequently work with data from HTML forms, user input, APIs, and other sources.

For example, an HTML input field commonly provides its value as a string, even when the user enters a number.

const quantity = "5";

console.log(typeof quantity); // "string"

If we want to perform a numeric calculation, we may need to convert that string into a number.

JavaScript sometimes performs this conversion automatically. This behavior is called type coercion.

Type coercion is the conversion of a value from one data type to another.

For example:

console.log("5" - 1); // 4

JavaScript converts the string "5" to the number 5 because the subtraction operator performs numeric subtraction.

However, automatic conversion does not always produce the result a developer expects.

console.log("5" + 1); // "51"

Here, + performs string concatenation instead of numeric addition.

JavaScript’s flexible conversion rules can be convenient, but they can also cause unexpected behavior.

The trade-off: Implicit conversion makes some expressions shorter, but it can make code harder to predict. It can also produce surprising results when comparing or calculating values of different types.

A good practice is to understand when JavaScript performs automatic conversion and use explicit conversion when the intended data type matters.

Arithmetic Operators

Arithmetic operators perform mathematical operations. They are used to calculate totals, averages, differences, percentages, indices, and many other values.

JavaScript provides these common arithmetic operators:

+, -, *, /, %, and **

3. Arithmetic Operators and Their Uses

Let’s understand how each operator works.

3.1 Addition (+)

The addition operator adds numeric values.

console.log(10 + 5); // 15

However, + can also join strings together. This process is called string concatenation.

console.log("Hello " + "World"); // "Hello World"

This makes + different from the other arithmetic operators.

3.2 Subtraction (-)

The subtraction operator subtracts the second operand from the first.

console.log(10 - 5); // 5

JavaScript can also convert a numeric string into a number during subtraction.

console.log("10" - 5); // 5

The string "10" is converted to the number 10.

3.3 Multiplication (*)

The multiplication operator multiplies two operands.

const price = 100;
const qty = 3;
console.log(price * qty); // 300

It is useful for calculating order totals, scaling values, and converting units.

JavaScript can also convert numeric strings during multiplication.

console.log("5" * "2"); // 10

Both strings are converted to numbers.

3.4 Division (/)

The division operator divides one operand by another.

console.log(20 / 4); // 5
console.log(10 / 3); // 3.3333333333333335

Division can produce a decimal result.

JavaScript also has special behavior when dividing by zero:

console.log(10 / 0); // Infinity
console.log(-10 / 0); // -Infinity
console.log(0 / 0); // NaN

NaN means Not-a-Number. It indicates that the result does not represent a valid number.

3.5 The Overloaded + Operator

An operator is called overloaded when it can perform different operations depending on the operands.

JavaScript’s + operator can perform numeric addition or string concatenation.

1 + 2;       // 3
"1" + 2; // "12"
2 + "1"; // "21"

In the first example, both operands are numbers, so JavaScript adds them.

In the second and third examples, the operands are converted to primitive values, and the presence of a string causes concatenation.

Consider a common problem with form inputs:

const a = "5";
const b = "3";

console.log(a + b); // "53"

The result is "53", not 8, because both operands are strings.

To perform numeric addition, convert the values explicitly:

const a = "5";
const b = "3";

console.log(Number(a) + Number(b)); // 8

Important: The simple rule that the + operator concatenates whenever either original operand is a string is useful for common examples, but JavaScript first applies primitive-conversion rules. Objects, for example, may be converted to primitives before the operation is selected.

3.6 Numeric Coercion with Other Arithmetic Operators

Unlike +, the arithmetic operators -, *, /, and % do not perform string concatenation. They generally convert string operands to numbers when performing their operations.

The exponentiation operator ** also uses numeric conversion rules for ordinary Number operands.

console.log("5" - "2"); // 3
console.log("5" * "2"); // 10
console.log("10" / "2"); // 5
console.log("7" % "3"); // 1
console.log("2" ** "3"); // 8

JavaScript also converts Boolean values to numbers in these numeric operations:

console.log(true - 1);  // 0
console.log(false + 5); // 5

This happens because true converts to 1 and false converts to 0 in these numeric contexts.

However, not every conversion succeeds:

console.log("hello" * 2); // NaN

The string "hello" cannot be converted into a valid number, so the multiplication produces NaN(Not a Number).

There are also exceptions to these general rules. For example, BigInt arithmetic does not allow mixing BigInt and Number operands in the same arithmetic operation.

console.log(2n + 1n); // 3n
// 2n + 1; // TypeError

The key lesson is that operators have specific conversion rules. Do not assume that all values will automatically convert successfully.

The Remainder Operator (%)

4. What Does % Do?

The % operator returns the remainder after division.

For example:

console.log(7 % 3); // 1

Why is the result 1?

When we divide 7 by 3, the quotient is 2 and the remainder is 1.

We can represent this as:

7 = 3 × 2 + 1

Therefore, 7 % 3 returns 1.

Another example:

console.log(12 % 4); // 0

There is no remainder because 12 is exactly divisible by 4.

4.1 Common Applications of %

The remainder operator is useful in many programming situations.

Checking whether a number is even or odd

const number = 8;
console.log(number % 2 === 0); // true

If a number is evenly divisible by 2, the remainder is 0.

Cycling through array indices

const nextIndex = (currentIndex + 1) % slides.length;

When currentIndex reaches the final slide, the expression returns to index 0, assuming the array is not empty.

This is funny… Let’s understand this simply. 😊

This is useful when building a carousel or slideshow where you want to move to the next slide. When you reach the last slide, it takes you back to the first slide.

  1. Imagine we have 4 slides
const slides = ["Slide 1", "Slide 2", "Slide 3", "Slide 4"];

JavaScript uses zero-based indexing, which means the first item’s index is 0, not 1.

Press enter or click to view image in full size
The indexes are 0, 1, 2, and 3. Therefore, slides.length is 4, but the last index is 3.

How does % help us return to the first slide?

Let’s say you are currently viewing the last slide.

const currentIndex = 3;
const nextIndex = (currentIndex + 1) % slides.length;

console.log(nextIndex); // 0

Let’s calculate it step by step:

Press enter or click to view image in full size

Remember this formula:

(currentIndex + 1) % slides.length
  • currentIndex + 1 moves to the next index.
  • % slides.length keeps the index within the valid range.
  • When the next index reaches the array length, the remainder becomes 0, returning to the first slide.

Important: This assumes slides.length > 0. If the array is empty, the expression involves division by zero and produces NaN, not a valid slide index.

The funny part is done! Now, let’s get back to using the remainder operator (%) and continue where we left off.

Formatting time

const totalSeconds = 125;
const seconds = totalSeconds % 60;
console.log(seconds); // 5

There are 5 seconds remaining after removing the complete minutes.

Arranging items in a grid

const index = 7;
const columns = 3;
console.log(index % columns); // 1

The remainder can help determine an item’s position within a row.

Remainder vs. True Mathematical Modulo

In everyday mathematics, modulo is often used to describe a positive wrap-around result. JavaScript’s % operator is technically a remainder operator, and its result follows the sign of the dividend (the left operand).

Consider negative values:

console.log(-5 % 3); // -2
console.log(-1 % 5); // -1

Why does -5 % 3 return -2?

JavaScript uses a quotient truncated toward zero:

-5 = 3 × (-1) + (-2)

Therefore, the remainder is -2.

In mathematical modulo arithmetic, the corresponding result for a positive divisor of 3 would be 1.

This difference matters when implementing circular navigation, especially when moving backward through a list.

So, JavaScript uses a division result that is truncated toward zero. This means it removes the decimal part without rounding away from zero.

Step 1: Divide -5 by 3.


-5 \ 3 = -1.666..

Step 2: Truncate the quotient toward zero.


-1.666.. --> -1

Step 3: Multiply the quotient by the divisor.


3*times (-1) = -3

Step 4: Find the remainder.

 -5 - (-3) = -2

Therefore:

console.log(-5 % 3); // -2

The formula is:

Remainder = a - (truncated (a/b) * b )

Here, a is the dividend (the left operand), and b is the divisor (the right operand).

3. Why does -1 % 5 return -1?

console.log(-1 % 5); // -1

Let’s calculate it:

-1 \ 5 = -0.2 

Truncate toward zero:

-0.2 --> 0 

Calculate the remainder:

-1 - (0 \times 5) = -1

So the answer is -1.

4. JavaScript remainder vs. mathematical modulo

The key difference is how negative results are handled.

Press enter or click to view image in full size

JavaScript’s remainder follows the sign of the dividend (the left operand), unless the result is zero.

Mathematical modulo with a positive divisor produces a non-negative result.

4.3 Implementing Positive Modulo

If you need a positive wrap-around result for a positive divisor, you can create a helper function:

function mod(a, b) {
return ((a % b) + b) % b;
}
console.log(mod(-1, 5)); // 4
console.log(mod(-5, 3)); // 1

This formula adjusts a negative remainder to produce a non-negative result when b is positive.

Note: This helper assumes a non-zero positive divisor for the intended wrap-around behavior. A zero divisor must be handled separately if it is possible in your application.

Exponentiation (**)

5. What Is Exponentiation?

Exponentiation raises a number to a power.

The ** operator was introduced in ECMAScript 2016 (ES2016).

console.log(2 ** 3); // 8

This means:

2 × 2 × 2 = 8

The equivalent operation can be written using Math.pow():

console.log(Math.pow(2, 3)); // 8

The ** syntax is shorter and often easier to read.

5.1 Right-Associativity

Exponentiation is right-associative. This means that when exponentiation operators appear consecutively without parentheses, the expression is grouped from right to left.

console.log(2 ** 3 ** 2); // 512

JavaScript evaluates this as:

2 ** (3 ** 2)

First:

3 ** 2 = 9

Then:

2 ** 9 = 512

It does not evaluate the expression as (2 ** 3) ** 2, which would produce 64.

Use parentheses when you want to make the order explicit.

5.2 Unary Minus and Syntax Restrictions

A unary minus is the negative sign applied to a single value.

In JavaScript, you cannot place a unary minus directly before the base of an exponentiation expression without parentheses.

// -2 ** 2; // SyntaxError

Instead, use parentheses to make your intention clear:

console.log((-2) ** 2); // 4
console.log(-(2 ** 2)); // -4

These expressions produce different results.

  • (-2) ** 2 squares the negative number, producing 4.
  • -(2 ** 2) calculates 2 squared first and then negates the result, producing -4.

5.3 BigInt Exponentiation

JavaScript supports BigInt values for integers that may be too large for the ordinary Number representation.

BigInt literals use the n suffix.

console.log(2n ** 10n); // 1024n

However, a negative exponent is not allowed for BigInt exponentiation.

// 2n ** -1n; // RangeError

The result would be a fraction, but BigInt represents integers only.

Remember that BigInt arithmetic has its own rules. Do not mix BigInt and Number operands in the same arithmetic expression without explicitly converting them where appropriate.

Comparison Operators

6. What Are Comparison Operators?

Comparison operators compare two operands and return a Boolean value.

The main comparison operators are:

Press enter or click to view image in full size

For example:

console.log(10 > 5);   // true
console.log(10 < 5); // false
console.log(10 >= 10); // true
console.log(5 !== 10); // true

Comparison operators are essential for validation, conditional statements, and automated test assertions.

Press enter or click to view image in full size

Consider these examples:

console.log(5 == "5");  // true
console.log(5 === "5"); // false

With ==, JavaScript converts the string "5" to a number before comparing.

With ===, the number 5 and the string "5" have different types, so the comparison returns false.

For most application code, prefer === and !== unless you intentionally need loose equality.

6.2 Reference vs. Value Comparison

JavaScript compares primitive values differently from objects.

Primitive values include numbers, strings, Booleans, null, undefined, BigInts, and Symbols.

Get Niluka Sripali Monnankulama’s stories in your inbox

Join Medium for free to get updates from this writer.

Primitive values are compared according to their values, with special rules for cases such as NaN and signed zero.

Objects, arrays, and functions are compared by identity, meaning whether they refer to the same object.

Consider two objects:

console.log({} === {}); // false

Why is the result false?

Each {} creates a new object. Even though both objects are empty, they are two separate objects.

The same applies to arrays:

console.log([1, 2] === [1, 2]); // false

The arrays contain the same values, but they are different objects.

If two variables refer to the same object, the comparison returns true:

const userA = { id: 1 };
const userB = userA;
console.log(userA === userB); // true

Both variables reference the same object.

6.3 Loose Equality Is Not Always Transitive

In mathematics, equality is transitive. If a = b and b = c, then a = c.

JavaScript’s loose equality does not always follow this property because it applies different conversion rules depending on the values being compared.

console.log(0 == "");  // true
console.log(0 == "0"); // true
console.log("" == "0"); // false

Here:

  • 0 == "" returns true.
  • 0 == "0" returns true.
  • "" == "0" returns false.

This is an example of why loose equality can be difficult to reason about.

Using strict equality avoids this particular source of unexpected conversion behavior.

So , JavaScript’s loose equality (==) works differently because it can convert values depending on the two operands being compared.

Let’s break down the three comparisons

Comparison 1: 0 == ""

0 → Number

“” → Empty string

An empty string is converted to the number 0.

0 == Number(""); // 0 == 0 → true

Comparison 2: 0 == "0"

0 → Number

“0” → String

The string "0" is converted to the number 0.

0 == Number("0"); // 0 == 0 → true

Comparison 3: "" == "0"

“” → String

“0” → String

Both operands are strings, so JavaScript compares their contents. One is empty and the other contains the character 0.

"" == "0"; // false

Again, why does transitivity fail?

The important point is that JavaScript does not convert all three values into one common type before comparing them.

Instead, it evaluates each pair separately:

Press enter or click to view image in full size

Therefore, even though the first two comparisons return true, the third returns false.

This is why loose equality is not always transitive.

Additionally, In JavaScript, loose equality can produce unexpected results due to implicit type conversion.

const actualValue = "";
const expectedValue = 0;

console.log(actualValue == expectedValue); // true
console.log(actualValue === expectedValue); // false
  • == allows type conversion before comparison.
  • === checks both the value and the type without performing that implicit conversion.

6.4 Special Rules for null and undefined

JavaScript treats null and undefined specially during loose equality comparisons.

console.log(null == undefined); // true
console.log(null == 0); // false
console.log(undefined == 0); // false

null == undefined returns true, but neither value loosely equals 0.

Think of these values as two different ways of representing a missing value:

  • null — intentionally represents no value.
  • undefined — usually means a value has not been assigned or is unavailable.

However, relational comparisons follow different conversion rules:

console.log(null >= 0); // true
console.log(null < 0); // false

For relational comparison, null is converted to the number 0.

This can look inconsistent, but equality and relational operators use different rules.

If you deliberately want to check whether a value is either null or undefined, this is a useful pattern:

if (value == null) {
console.log("Value is null or undefined");
}

This is one of the few cases where using == intentionally can be helpful. It matches null and undefined, but not ordinary values such as 0 or "".

If you need to distinguish between null and undefined, use strict equality instead.

console.log(null === undefined);

Strict equality checks types too, and these are different types.

6.5 The Special Case of NaN

NaN means Not-a-Number. It can appear when a numeric operation or conversion does not produce a valid number.

console.log(Number("hello")); // NaN

NaN has a special comparison rule: it is not equal to any value, including itself.

console.log(NaN === NaN); // false
console.log(NaN == NaN); // false

NaN is a special exception. JavaScript defines NaN as unequal to every value when using either == or ===, including itself.

Think of NaN as indicating an invalid numeric result rather than a normal number you can compare.

Use Number.isNaN() to check whether a value is actually NaN:

console.log(Number.isNaN(NaN));     // true
console.log(Number.isNaN("hello")); // false

Number.isNaN() does not automatically convert its argument to a number.

Object.is() can also recognize NaN:

console.log(Object.is(NaN, NaN)); // true

For ordinary numeric validation, Number.isNaN() is usually the clearer choice.

6.6 Positive Zero and Negative Zero

JavaScript has both positive zero (+0) and negative zero (-0) in its Number representation.

Strict equality treats them as equal:

console.log(+0 === -0); // true

However, Object.is() distinguishes them:

console.log(Object.is(+0, -0)); // false

This distinction rarely matters in everyday application code, but it can be important in specialized mathematical calculations.

6.7 String Comparison Uses Lexicographical Ordering

When both operands are strings, relational operators compare them lexicographically, using the sequence of string code units rather than treating them as numbers.

console.log("10" < "9"); // true

Why?

The first characters are compared. The character "1" comes before "9", so "10" is considered less than "9" in string comparison.

Now compare a string with a number:

console.log("10" < 9); // false

Here, JavaScript converts "10" to the number 10, then evaluates 10 < 9.

The result is false.

Practical lesson: If values represent numbers, convert them to numbers before comparing. Do not rely on string ordering for numeric data.

Logical Operators and Short-Circuit Control Flow

7. Understanding Logical Operators

JavaScript provides three common logical operators:

Press enter or click to view image in full size

Unlike many beginners expect, && and || do not always return Boolean values. They can return one of the original operands.

To understand why, we first need to understand truthy and falsy values.

7.1 Truthy and Falsy Values

In JavaScript, values are evaluated as truthy or falsy when used in a Boolean context, such as an if statement or a logical expression.

The following values are falsy:

  • false
  • 0
  • -0
  • 0n
  • "" (an empty string)
  • null
  • undefined
  • NaN

All other values are truthy, including values that may look empty or false-like.

For example:

console.log(Boolean([]));      // true
console.log(Boolean({})); // true
console.log(Boolean("0")); // true
console.log(Boolean("false")); // true

An empty array and an empty object are truthy. A non-empty string containing "false" is also truthy.

This is important because JavaScript does not treat the string "false" as the Boolean value false.

7.2 Logical AND (&&)

The && operator evaluates operands from left to right.

  • If it encounters a falsy operand, it returns that operand and stops.
  • If every operand is truthy, it returns the last operand.

Example:

console.log(true && false); // false
console.log("Hello" && "World"); // "World"
console.log(0 && "Hello"); // 0

In the second example, both strings are truthy, so the result is the last operand, "World".

In the third example, 0 is falsy, so JavaScript stops and returns 0.

A practical example is conditional execution:

const isLoggedIn = true;
isLoggedIn && console.log("Welcome back!");

Because isLoggedIn is truthy, JavaScript evaluates the second operand and prints the message.

7.3 Logical OR (||)

The || operator also evaluates operands from left to right.

  • If it encounters a truthy operand, it returns that operand and stops.
  • If all operands are falsy, it returns the last operand.
console.log(false || true); // true
console.log("" || "Guest"); // "Guest"
console.log(0 || 10); // 10

This behavior is commonly used to provide fallback values.

const username = "";
const displayName = username || "Guest";
console.log(displayName); // "Guest"

Because an empty string is falsy, the expression returns "Guest".

However, this can be a problem when 0, false, or "" is a valid value that should be preserved.

7.4 Nullish Coalescing (??)

The nullish coalescing operator (??) provides a fallback only when the left operand is null or undefined.

console.log(null ?? "Default");      // "Default"
console.log(undefined ?? "Default"); // "Default"

Unlike ||, it preserves other falsy values.

console.log(0 ?? 10);      // 0
console.log(false ?? true); // false
console.log("" ?? "Guest"); // ""

Compare these two expressions:

const count1 = 0 || 10;
const count2 = 0 ?? 10;
console.log(count1); // 10
console.log(count2); // 0

The first expression returns 10 because 0 is falsy.

The second expression returns 0 because zero is neither null nor undefined.

Use ?? when zero, false, or an empty string is a valid value that should not be replaced by a default.

7.5 Short-Circuiting

Short-circuiting means JavaScript stops evaluating an expression when the result can already be determined.

For example:

false && console.log("This will not run");
true || console.log("This will not run");

Neither message is printed.

  • With &&, a falsy left operand means the overall expression will be falsy, so JavaScript does not evaluate the right operand.
  • With ||, a truthy left operand means the expression already has a truthy result, so JavaScript does not evaluate the right operand.

This behavior is useful, but it is important to remember that the right-hand expression may not execute.

Safe Coding Best Practices

Understanding how operators work helps us write code that is more predictable and easier to maintain.

8.1 Prefer === and !==

Strict equality avoids unexpected type coercion during comparisons.

console.log(5 === "5"); // false

Use loose equality only when its conversion behavior is intentional.

8.2 Handle null and undefined Deliberately

If your intention is to catch both null and undefined, this pattern is useful:

if (value == null) {
// Handles null and undefined
}

If you want to check for one specific value, use strict equality:

if (value === null) {
// Handles only null
}

Choose the comparison based on what your code actually needs.

8.3 Use Number.isNaN() to Check for NaN

Do not compare a value directly with NaN.

Incorrect:

value === NaN; // Always false when value is NaN

Correct:

Number.isNaN(value);

This makes the intention clear and avoids unexpected comparisons.

8.4 Use ?? When Falsy Values Are Valid

Consider an application where 0 is a valid quantity:

const quantity = 0;

const displayedQuantity = quantity ?? 1;
console.log(displayedQuantity); // 0

Using quantity || 1 would return 1, because zero is falsy.

Use ?? when you want to replace only missing (null or undefined) values.

8.5 Convert Types Explicitly

When a calculation requires numbers, convert values deliberately.

const price = "100";
const quantity = "3";

const total = Number(price) * Number(quantity);
console.log(total); // 300

For other situations, JavaScript provides conversion functions such as String() and Boolean().

Remember that conversion does not guarantee valid input:

console.log(Number("hello")); // NaN

Validate converted values when they come from user input or external systems.

8.6 Use Explicit Comparator Functions for Numeric Sorting

JavaScript’s default Array.prototype.sort() converts elements to strings and sorts them lexicographically.

console.log([1, 2, 10].sort());
// [1, 10, 2]

This may be unexpected when you want numeric sorting.

Provide a comparator function instead:

console.log([1, 2, 10].sort((a, b) => a - b));
// [1, 2, 10]

The comparator returns a negative number when a should come before b, a positive number when a should come after b, and zero when they are equal for sorting purposes.

This approach is useful when sorting prices, scores, IDs represented as numbers, or other numeric values.

8.7 Use Parentheses to Make Complex Expressions Clear

Operator precedence determines the order in which operations are evaluated.

console.log(2 + 3 * 4); // 14

Multiplication is evaluated before addition.

If you want addition to happen first, use parentheses:

console.log((2 + 3) * 4); // 20

Parentheses make the intended calculation clear to both JavaScript and the person reading your code.

8.8 Test Edge Cases

When writing application code or automation tests, do not test only ordinary values.

Depending on the requirements, consider values such as:

  • 0 and negative numbers
  • Empty strings ("")
  • null and undefined
  • Invalid numeric strings
  • Values with different data types
  • Empty arrays and objects
  • Boundary values and very large numbers

These cases can reveal unexpected operator behavior and help prevent bugs.

Why These Concepts Matter for QA Engineers

JavaScript operators and coercion are especially relevant to QA engineers who write automation tests, validate API responses, or investigate unexpected application behavior.

Imagine an API returns a quantity as a string:

const price = 100;
const quantity = "3";

const actualTotal = price + quantity;
const expectedTotal = 300;
console.log(actualTotal); // "1003"
console.log(actualTotal === expectedTotal); // false

The problem is not the multiplication formula. The problem is that the + operator performs string concatenation in this expression.

The corrected version is:

const price = 100;
const quantity = "3";

const actualTotal = price * Number(quantity);
const expectedTotal = 300;
console.log(actualTotal); // 300
console.log(actualTotal === expectedTotal); // true

This is a simple example of how understanding operators can help identify application defects.

As a QA engineer, pay attention to:

  1. Data types: Is an API field a string when the contract requires a number?
  2. Equality: Does the test validate the exact expected value and type?
  3. Conditions: Are all required conditions being checked?
  4. Numeric calculations: Can implicit conversion change the result?
  5. Fallback values: Should the application preserve valid values such as 0 and false?
  6. Edge cases: What happens when data is missing, invalid, or unexpectedly formatted?

For example, strict assertions can help detect an API contract violation:

const actualId = "101";
const expectedId = 101;

console.log(actualId === expectedId); // false

The values look similar, but their types differ. Whether that is a defect depends on the API contract and the test requirement.

The goal is not to make every comparison strict without thinking. The goal is to understand the expected behavior and write tests that verify it accurately.

Conclusion

JavaScript operators are fundamental to writing reliable programs. They allow us to perform calculations, compare values, evaluate conditions, and control how expressions are executed.

However, knowing the symbols is only the beginning. We must also understand how JavaScript converts data types and evaluates expressions.

Here are the key takeaways from this blog:

  • Operands are the values or variables used in an operation; operators perform the operation.
  • Type coercion is the automatic conversion of values from one data type to another.
  • The + operator can perform numeric addition or string concatenation.
  • The % operator returns a remainder, which can differ from mathematical modulo for negative values.
  • The ** operator performs exponentiation and has specific associativity and syntax rules.
  • Loose equality (==) can produce surprising results because it performs type coercion.
  • Strict equality (===) is generally the safer default when comparing values.
  • Objects and arrays are compared by identity, not simply by their contents.
  • Logical operators use truthy and falsy values and can return operands instead of Boolean values.
  • The ?? operator is useful when a fallback should apply only to null or undefined.
  • Explicit conversion, clear expressions, and edge-case testing help prevent unexpected behavior.

If you are learning JavaScript for web development or QA automation, practise these concepts with small examples and test different data types. A solid understanding of operators and coercion will help you debug JavaScript code, write stronger automated tests, and move on to more advanced topics with confidence.

Keep learning, keep practising, and keep testing!

--

--

Niluka Sripali Monnankulama
Niluka Sripali Monnankulama

Written by Niluka Sripali Monnankulama

Tech enthusiast & writer | Software engineer, Test automation Engineer |Part of an Amazing Team| Passionate about life, nature & creative storytelling. ✨

Many Minds
Many Minds

Published in Many Minds

The idea is to learn something for myself and share what I have learned.