Demystifying JavaScript Operators: What Does That Symbol Mean?
In this article, we’re going to examine the operators in JavaScript one by one. We’ll explain their function and demonstrate their usage, helping you to grasp their role in building more complex expressions.
What are JavaScript Operators?
JavaScript, a cornerstone of modern web development, is a robust language full of numerous features and constructs. Among these, operators (special symbols such as +
, +=
, &&
, or ...
) play an essential role, enabling us to perform different types of calculations and manipulations on variables and values.
Despite their importance, operators can sometimes be a source of confusion for new programmers and seasoned coders alike.
Take a moment to examine this code snippet:
const x = 10, y = 20, z = 30;
console.log((x > y ? x : y) > z ? (x > y ? x : y) : z);
// WTF?
Don’t be alarmed if it seems a bit cryptic. By the time we’re finished, you’ll be able to understand exactly what it does.
A Quick Word on Terminology
Before we dive in, let’s clarify a couple of terms that we’ll be using quite a bit:
-
An operand is the item that operators work on. If we think of an operator as a kind of action, the operand is what the action is applied to. For example, in the expression 5 + 3,
+
is the operator (the action of addition), and 5 and 3 are the operands — the numbers being added together. In JavaScript, operands can be of various types, such as numbers, strings, variables, or even more complex expressions. -
Coercion is the process of converting a value from one primitive type to another. For example, JavaScript might change a number into a string, or a non-Boolean value into a Boolean. The primitive types in JavaScript are
String
,Number
,BigInt
,Boolean
,undefined
,Symbol
ornull
. -
NaN
stands for Not a Number. It’s a special value of theNumber
type that represents an invalid or unrepresentable numeric value. -
Truthy values are those that evaluate to
true
in a Boolean context, while falsy values evaluate tofalse
— with falsy values beingfalse
,0
,-0
,''
,null
,undefined
,NaN
andBigInt(0)
. You can read more about truthy and falsy values in Truthy and Falsy Values: When All is Not Equal in JavaScript.
As we explore JavaScript operators, we’ll see these concepts in action and get a better understanding of how they influence the results of our operations.
Arithmetic Operators
Arithmetic operators allow us to perform arithmetic operations on values and to transform data. The commonly used arithmetic operators in JavaScript include addition (+
), subtraction (-
), multiplication (*
), and division (/
). Beyond these, we also have the modulus operator (%
), which returns the remainder of a division operation, and the increment (++
) and decrement (--
) operators that modify a value by one.
Addition: +
The addition operator performs two distinct operations: numeric addition and string concatenation. When evaluating expressions using the +
operator, JavaScript first coerces both operands to primitive values. Once this is done, it examines the types of both operands.
If one operand is a string, the other operand is also converted to a string, and then the two strings are concatenated. For example:
'Hello, ' + 'World!' // Hello, World!
'The number is ' + 42 // 'The number is 42'
If both operands are BigInts
, BigInt
addition is performed. A BigInt
is a special numeric type that can deal with numbers larger than the standard Number
type can handle.
But if one operand is a BigInt
and the other isn’t, JavaScript throws a TypeError
:
const num1 = BigInt(12345678901234567890);
const num2 = BigInt(12345678901234567890);
num1 + num2 // 24691357802469134336n
num1 + 1 // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
For all other cases, both operands are converted to numbers, and numeric addition is performed. For example:
10 + 20 // 30
10 + true // 11 — true is converted to a value of 1
Be aware that JavaScript sometimes has a strange idea of what this looks like:
1 + { a: 1 } // '1[object Object]'
In this case, JavaScript tried to convert the object { a: 1 }
to a primitive value, but the best it could do was to convert it to the string [object Object]
, which then got concatenated with the number 1.
Subtraction: -
The subtraction operator in JavaScript is straightforward in its usage: it’s used to subtract one number from another. Like the addition operator, it also works with the BigInt
type.
If both operands are numbers or can be converted to numbers, JavaScript performs numeric subtraction:
10 - 3 // 7
'100' - 30 // 70
If both operands are BigInts
, JavaScript performs BigInt
subtraction:
const num1 = BigInt('9007199254740993');
const num2 = BigInt('3');
num1 - num2 // 9007199254740990n
Like the addition operator, subtraction can also produce unexpected results when used with non-numbers. For example, if we try to subtract a something that can’t be converted to a number, JavaScript will return NaN
, which stands for “Not a Number”:
10 - 'Jim' // NaN
Multiplication: *
The multiplication operator works with numbers and BigInts.
Normally, we’ll be multiplying numbers:
10 * 5 // 50
If both operands are BigInts
, then it performs BigInt
multiplication:
const num1 = 9007199254740993n;
num1 * 2n // 18014398509481986n
As with other operators, JavaScript attempts to convert non-numeric values into numbers. If it can’t do this, it returns NaN
:
'100' * 30 // 3000
10 * 'Jim' // NaN
Division: /
The division operator (/
) functions with numbers and BigInts
, much the same way as +
, -
and *
. It first converts both operands into numbers.
Standard number division:
10 / 2 // 5
10 / '2' // 5
When dealing with BigInts
, the division operator behaves slightly differently. It performs the division and discards any remainder, effectively truncating the result towards zero:
const num = 10n;
num / 3n // 3n, not 3.333...n
Dividing a number by zero will produce Infinity
, unless it’s a BigInt
, in which case it throws a RangeError
.
If we attempt to divide a number by a value that can’t be converted into a number, JavaScript will usually return NaN
.
Modulus (remainder): %
The modulus operator is used to find the remainder after division of one number by another (known as the dividend and the divisor). This arithmetic operator works with numbers and BigInts
.
When we use the %
operator, JavaScript first converts the operands to numbers:
10 % 3 // 1
'10' % 3 // 1
This is because three goes into ten three times (making nine), and what’s left over (the remainder) is one.
A common use case for this operator is to check if a number is odd or even:
const isEven = num => num % 2 === 0;
isEven(1) // false
isEven(2) // true
This uses an arrow function and the triple equals operator that we’ll meet later on.
The modulus operator has some special cases. For example, if one of the operands is NaN
, if the dividend is Infinity
, or if the divisor is 0
, the operation returns NaN
.
On the other hand, if the divisor is Infinity
or if the dividend is 0
, the operation returns the dividend.
Increment: ++
The increment operator is used to increase the value of a variable by 1. It can be applied to operands of type Number
or BigInt
, and its behavior can differ based on whether it’s used in postfix or prefix form.
Postfix increment
If the operator is placed after the operand (num++
), the increment operation is performed after the value is returned. In this case, the original value of the variable is used in the current expression, and the variable’s value is incremented afterward:
let num = 5;
const result = num++;
console.log(result); // 5
console.log(num); // 6
Prefix increment
If the operator is placed before the operand (++num
), the increment operation is performed before the value is returned. In this case, the variable’s value is incremented first, and then the updated value is used in the current expression:
let num = 5;
const result = ++num;
console.log(result); // 6
console.log(num); // 6
Decrement: --
The decrement operator is used to decrease the value of a variable by 1. Similar to the increment operator, it can be applied to operands of type Number
or BigInt
. The behavior of the decrement operator can vary based on whether it’s used in postfix or prefix form.
Postfix decrement
When the operator is placed after the operand (num--
), the decrement operation is performed after the value is returned. In this case, the original value of the variable is used in the current expression, and the variable’s value is decremented afterward:
let num = 5;
const result = num--;
console.log(result); // 5
console.log(num); // 4
Prefix decrement
When the operator is placed before the operand (--num
), the decrement operation is performed before the value is returned. In this case, the variable’s value is decremented first, and then the updated value is used in the current expression:
let num = 5;
const result = --num;
console.log(result); // 4
console.log(num); // 4
The decrement operator, just like the increment operator, can only be used with variables that can be changed:
const num = 5;
const result = num--; // Uncaught TypeError: Assignment to constant variable.
Miscellaneous arithmetic operators
In addition to the increment and decrement operators, there are other arithmetic operators in JavaScript that we should be aware of.
The unary negation operator (-
) is used to negate a numeric value, changing its sign to the opposite. For example, -5
would be the negation of the number 5
.
The unary plus operator (+
) can be used to explicitly convert a value to a number, which can be useful when dealing with string representations of numbers. For example, +'10'
converts the string '10'
to the number 10
:
const num = '10';
const res = +num; // unary operator converts String to Number
res // 10
The exponentiation operator (**
) is used to raise a number to a power. For example, 2 ** 3
represents 2 raised to the power of 3, which results in 8.
It’s also important to note that JavaScript follows operator precedence rules, which determine the order in which operators are evaluated in an expression. For example, multiplication and division have a higher precedence than addition and subtraction, so they are evaluated first:
const result = 10 + 5 * 2; // Multiplication is evaluated first
console.log(result); // 20
We can alter the order of evaluation by using the grouping operator ()
, which is covered in the “Grouping operator” section below.
Assignment Operators
Assignment operators are used to assign values to variables. They also offer a concise and effective way to update the value of a variable based on an expression or other value. In addition to the basic assignment operator (=
), JavaScript provides compound assignment operators that combine arithmetic or logical operations with assignment.
Assignment: =
This operator is used to assign a value to a variable. It allows us to store a value in a variable so that we can use and reference it later in our code:
const num = 4; // Assign the value 4 to the variable num
const squared = num * num; // Assign the value 16 to the variable squared
The assignment operator assigns the value on the right-hand side of the operator to the variable on the left-hand side.
Additionally, the =
operator can be chained to assign the same value to multiple variables in a single line:
const a = b = c = 10; // Assign the value 10 to variables a, b, and c
console.log(a, b, c); // 10 10 10
Addition assignment: +=
The addition assignment operator is a compound operator that performs an operation and assignment in one step. Specifically, it adds the right operand to the left operand and then assigns the result to the left operand:
let num = 10;
num += 5 // 15
This operator isn’t limited to numbers. It can also be used for string concatenation:
let greeting = 'Hello, ';
greeting += 'World!' // 'Hello, World!'
When the operands aren’t of the same type, JavaScript applies the same rules of type coercion that we saw previously:
let greeting = 'Hello, ';
greeting += 42 // 'Hello, 42'
Subtraction assignment: -=
The subtraction assignment operator is another compound operator that performs an operation and assignment in one step. It subtracts the right operand from the left operand and then assigns the result to the left operand:
let num = 10;
num -= 5 // 5
Like other JavaScript operators, -=
performs type coercion when the operands aren’t of the same type. If an operand can be converted to a number, JavaScript will do so:
let num = '10';
num -= 5 // num is now 5 (number), not '5' (string)
Otherwise, the result is NaN
:
let name = 'Jim';
name -= 5 // NaN
Multiplication assignment: *=
The multiplication assignment operator multiplies the left operand by the right operand and then assigns the result back to the left operand:
let num = 5;
num *= 3 // 15
When we use operands of different types, JavaScript will try to convert non-numeric string operands to numbers:
let num = '5';
num *= 3 // num is now 15 (number), not '15' (string)
If the string operand can’t be converted to a number, the result is NaN
.
Division assignment: /=
Like its siblings, the division assignment operator performs an operation on the two operands and then assigns the result back to the left operand:
let num = 10;
num /= 2 // 5
Otherwise, the rules we discussed for the division operator above apply:
let num = 3;
num /= '-0.5' // -6
num = 3;
num /= 0 // Infinity
num = 3;
num /= 'Jim' // NaN
Modulus assignment: %=
The modulus assignment operator performs a modulus operation on the two operands and assigns the result to the left operand:
let num = 10;
num %= 3 // 1
Otherwise, the rules we discussed for the modulus operator apply:
let num = 3;
num %= '3' // 0
num = 3;
num %= 0 // NaN
num = 3;
num %= 'Jim' // NaN
Exponentiation assignment: **=
The exponentiation assignment operator performs exponentiation, where the left operand is the base and the right operand is the exponent, and assigns the result to the left operand:
let num = 2;
num **= 3 // 8
Here, num
is raised to the power of 3, and the result (8) is assigned back to num
.
As before, when the second operand is not a number, JavaScript will attempt to convert it with varying degrees of success:
let num = 2;
num **= '3' // 8
num = 2;
num **= 'Jim' // NaN
Bitwise assignment operators
While we’ve been focusing on arithmetic operators so far, JavaScript also supports a set of assignment operators that work at the bit level. These are the bitwise assignment operators. If you’re familiar with binary numbers and bit manipulation, these operators will be right up your alley.
These operators include:
- Bitwise AND assignment (
&=
) - Bitwise OR assignment (
|=
) - Bitwise XOR assignment (
^=
) - Left shift assignment (
<<=
) - Right shift assignment (
>>=
) - Unsigned right shift assignment (
>>>=
)
Each of these JavaScript assignment operators performs a specific bitwise operation on the binary representations of the numbers involved and assigns the result back to the left operand.
We’ll explore bitwise operators in more detail in the “Bitwise Operators” section below.
Comparison Operators
Leaving the realm of arithmetic, let’s dive into another significant group of JavaScript operators — the comparison operators. As the name implies, comparison operators are used to compare values and return a Boolean result. Comparison operators are the underpinning of many programming decisions and control structures — from simple condition checks to complex logical operations.
Equality: ==
The equality operator is used to check whether two values are equal to each other. It returns a Boolean result. However, it’s important to note that this comparison operator performs a loose equality check, meaning that if the operands are of different types, JavaScript will try to convert them to a common type before making the comparison:
1 == 1 // true, both operands are numbers
1 == '1' // true, string is converted to a number
Things get slightly more complicated dealing with objects and arrays. The ==
operator checks whether they refer to the same location in memory, not whether their contents are identical:
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
array1 == array2 // false, even though they look the same
const array3 = array1;
array1 == array3; // true, they refer to the same memory location
In this case, JavaScript doesn’t attempt to convert and compare the values within the objects or arrays. Instead, it checks whether they’re the same object (that is, whether they occupy the same memory space).
You can read more about loose equality comparisons here.
Inequality: !=
The inequality operator is used to check whether two values are not equal to each other. Like the ==
operator, it performs a loose inequality check. This means that, if they’re of different types, it will try to convert the operands to a common type before making the comparison:
1 != 2 // true, 1 is not equal to 2
1 != '1' // false, string is converted to a number, 1 is equal to 1
'apple' != 'orange' // true, strings are different
Similar to the ==
operator, when comparing objects and arrays, the !=
operator checks whether they refer to the same memory location, not whether their content is identical.
Strict equality (===
) and strict inequality (!==
)
The strict equality and strict inequality comparison operators are similar to their non-strict counterparts (==
and !=
), but they don’t perform type coercion. If the operands are of different types, they’re considered different, no matter their values.
Here’s how they work:
1 === '1' // false, because Number is not strictly equal to String
1 !== '1' // true, because Number is strictly not equal to String
null === undefined // false, even though null == undefined is true
true === 1 // false, because Boolean is not strictly equal to Number
For objects and arrays, the strict equality operator behaves the same way as the loose equality operator: it checks whether they refer to the same object, not whether their contents are identical.
NaN
is a special case. It’s the only value in JavaScript that isn’t strictly equal to itself:
NaN === NaN // false
You can read more about strict equality comparisons here.
Greater than: >
The greater than operator checks if the left operand is greater than the right operand, returning a Boolean result. This comparison is straightforward with numeric values:
4 > 3 // true
2 > 2 // false
When comparing non-numeric values, JavaScript applies a process of conversion to make them comparable. If both values are strings, they’re compared based on their corresponding positions in the Unicode character set:
'3' > '2' // true
'abc' > 'def' // false
If one or both of the operands aren’t strings, JavaScript tries to convert them to numeric values for the comparison:
'10' > 2 // true, '10' is converted to a number before comparison
Certain special rules apply for specific values during this conversion. For instance, null
is converted to 0
, undefined
is converted to NaN
, and Boolean values true
and false
are converted to 1
and 0
respectively. However, if either value is NaN
after conversion, the operator will always return false
:
10 > 'Jim' // false, converting 'Jim' to a number yields NaN
Less than: <
The less than operator returns true
if the left operand is less than the right operand, and false
otherwise. The same rules apply as for the greater than operator; only the order of operands is reversed:
5 < 10 // true, 5 is less than 10
'10' < '2' // true, because the comparison is lexicographical
'10' < 2 // false, String '10' is coerced to a Number
Like the >
operator, the <
operator uses coercion to convert operands to a common type before making the comparison.
Greater than or equal to (>=
) and less than or equal to (<=
)
The greater than or equal to (>=
) and less than or equal to (<=
) operators function similarly to their <
and >
counterparts, with the added condition of equality.
For the >=
operator, it returns true
if the left operand is greater than or equal to the right operand, and false
otherwise. Conversely, the <=
operator returns true
if the left operand is less than or equal to the right operand, and false
otherwise. Coercion rules and type conversion, as explained in the sections on <
and >
directly above, apply here as well:
5 >= 5 // true, 5 is equal to 5
5 >= 6 // false, 5 is not greater than 6
'10' >= '2' // false, Unicode for '1' is 49, while Unicode for '2' is 50
'10' <= 20 // true, String '10' is coerced to a Number
5 >= false // true, false is coerced to 0
5 <= true // false, true is coerced to 1
null >= -1 // true, null is coerced to 0
undefined <= 0 // false, undefined is coerced to NaN
Logical Operators
Logical operators in JavaScript offer a way to work with multiple conditions simultaneously. They’re an integral part of decision-making constructs in programming, such as if
statements, and for
loops.
Mastering logical operators is key for controlling the flow of our code.
Logical AND: &&
When used with Boolean values, the logical AND operator returns true if all conditions are true
and false
otherwise.
However, with non-Boolean values, it gets more interesting:
- The operator evaluates conditions from left to right.
- If it encounters a value that can be converted to
false
(known as a falsy value), it stops and returns that value. - If all values are truthy, it returns the last truthy value.
For example:
true && true // true
true && false // false
'apple' && 'banana' // 'banana'
'' && 'banana' // ''
The &&
operator’s ability to return the value of the operands makes it a versatile tool for conditional execution and setting default values. For example, we can use the &&
operator to execute a function or a block of code only if a certain condition is met:
const userIsLoggedIn = true;
userIsLoggedIn && renderWelcomeMessage();
In this case, renderWelcomeMessage
will only be executed if userIsLoggedIn
is true
. If userIsLoggedIn
is false
, the operation will stop at userIsLoggedIn
and renderWelcomeMessage
won’t be called. This pattern is often used with React to conditionally render components.
Logical OR: ||
When used with Boolean values, the logical OR operator returns true
if at least one condition is true
and false
otherwise.
It can also return non-Boolean values, performing what’s known as short-circuit evaluation. It evaluates conditions from left to right, stopping and returning the value of the first truthy condition encountered. If all conditions are falsy, it returns the last falsy value:
true || false // true
false || true // true
'Hello' || 'World' // 'Hello'
'' || 'World' // 'World'
0 || '' // ''
Logical NOT: !
The logical NOT operator is used to reverse the Boolean value of a condition or expression. Unlike the &&
and ||
operators, the !
operator always returns a Boolean value.
If the condition is truthy (that is, it can be converted to true
), the operator returns false
. If the condition is falsy (that is, it can be converted to false
), the operator returns true
:
!true // false
!false // true
!'Hello' // false
!'' // true
!0 // true
We can use the !
operator twice to convert a value to its Boolean equivalent:
!!'Hello' // true
!!'' // false
!!0 // false
Nullish coalescing operator: ??
The nullish coalescing operator checks whether the value on its left is null
or undefined
, and if so, it returns the value on the right. Otherwise, it returns the value on the left.
Though similar to the ||
operator in some respects, the ??
operator differs in its handling of falsy values.
Whereas the ||
operator returns the right-hand operand if the left-hand operand is any falsy value (such as null
, undefined
, false
, 0
, NaN
, ''
), the ??
operator only does so when the left-hand operand is null
or undefined
:
null ?? 'default string' // 'default string'
undefined ?? 'default string' // 'default string'
'' ?? 'default string' // ''
0 ?? 100 // 0
Setting default values with logical operators
The ||
and ??
logical operators are useful for setting default values in programs. Here’s an example of doing this with the ||
operator:
const userColorPreference = null;
const defaultColor = 'blue';
const color = userColorPreference || defaultColor; // 'blue'
Here’s an example with the ??
operator:
const userColorPreference = null;
const defaultColor = 'blue';
const color = userColorPreference ?? defaultColor; // 'blue'
The main difference between these logical operators (as highlighted above) is how they treat falsy values:
const userColorPreference = '';
const defaultColor = 'blue';
const color1 = userColorPreference || defaultColor; // 'blue'
const color2 = userColorPreference ?? defaultColor; // ''
Bitwise Operators
Bitwise operators in JavaScript offer a way to perform operations at the binary level, directly manipulating bits in a number’s binary representation. While these operators can be instrumental in specific tasks like data encoding, decoding, and processing, they’re not frequently used in day-to-day JavaScript programming.
In this article, we’ll provide an overview of these operators so you can recognize and understand them, but we won’t delve deeply into their usage given their relatively niche application.
Bitwise AND: &
The bitwise AND operator performs a bitwise AND operation on the binary representations of integers. It returns a new number whose bits are set to 1 if the bits in the same position in both operands are 1. Otherwise, it sets them to 0:
// 5 in binary: 101
// 3 in binary: 011
5 & 3 // 1 (which is 001 in binary)
Bitwise OR: |
The bitwise OR operator works similarly to the &
operator, but it sets a bit to 1 if at least one of the bits in the same position in the operands is 1:
// 5 in binary: 101
// 3 in binary: 011
5 | 3 // 7 (which is 111 in binary)
Bitwise XOR: ^
The bitwise XOR operator is a little different. It sets a bit to 1 only if the bits in the same position in the operands are different (one is 1 and the other is 0):
// 5 in binary: 101
// 3 in binary: 011
5 ^ 3 // 6 (which is 110 in binary)
Bitwise NOT: ~
The bitwise NOT operator (~
) inverts the bits of its operand. It switches 1s to 0s and 0s to 1s in the binary representation of a number:
// 5 in binary: 101
~5 // -6 (which is the two's complement of 101, i.e., 010)
Note: two’s complement is a method for representing negative integers in binary notation.
Bitwise shift operators: <<, >>, >>>
Bitwise shift operators are used to shift the bits of a binary number to the left or right. In JavaScript, there are three types: left shift (<<
), right shift (>>
), and zero-fill right shift (>>>
).
The left shift bitwise operator (<<
) moves bits to the left and fills in with zeros on the right. The right shift operator (>>
) shifts bits to the right, discarding bits shifted off. The zero-fill right shift operator (>>>
) also shifts bits to the right but fills in zeros on the left.
These operators are less common in everyday JavaScript coding, but they have uses in more specialized areas like low-level programming, binary data manipulation, and some types of mathematical calculations.
Other Operators
Apart from the commonly used arithmetic, comparison, logical, and bitwise operators, JavaScript offers a variety of unique operators for specific purposes. These include operators for handling conditional logic, managing object properties, controlling the order of operations, and more.
Conditional (ternary) operator: ? :
The conditional ternary operator (? :
) is a concise way to make decisions in our JavaScript code. It gets its name from being the only operator that takes three operands. The syntax for this conditional operator is as follows:
condition ? expressionIfTrue : expressionIfFalse.
The operator works by first evaluating the condition. If the condition is true
, it executes the expressionIfTrue
, and if it’s false
, it executes the expressionIfFalse
:
const age = 15;
const status = age >= 18 ? 'Adult' : 'Minor'; // 'Minor'
In the code above, the ternary operator checks if age
is greater than or equal to 18. Since age is 15, the condition evaluates to false
, and 'Minor'
is assigned to the status
variable.
This operator can be a handy way to write concise if–else statements, but it can also make code more difficult to read if overused or used in complex conditions.
Spread operator: ...
The spread operator (...
) allows elements of an iterable (such as an array or a string) to be expanded in places where zero or more arguments or elements are expected. It can be used in function calls, array literals, and object literals:
// In function calls
const numbers = [1, 2, 3];
console.log(...numbers); // 1 2 3
// In array literals
const moreNumbers = [4, 5, ...numbers];
console.log(moreNumbers); // [4, 5, 1, 2, 3]
// In object literals
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }
The spread operator can be a handy tool for creating copies of arrays or objects, concatenating arrays, or passing the elements of an array as arguments to a function.
You can read more about the spread operator in Quick Tip: How to Use the Spread Operator in JavaScript.
Comma operator: ,
The comma operator (,
) allows multiple expressions to be evaluated in a sequence and returns the result of the last expression. The expressions are evaluated from left to right.
It’s particularly useful when we need to include multiple expressions in a location that only allows for one, such as in the initialization or update sections of a for loop:
for(let i = 0, j = 10; i <= 10; i++, j--) {
console.log(`i: ${i}, j: ${j}`);
}
In the code above, the comma operator is used to declare and update two variables (i
and j
) in the for loop.
Optional chaining operator: ?.
Optional chaining is a relatively recent addition to JavaScript (as of ES2020) that simplifies the process of accessing deeply nested properties of objects. It helps us to write cleaner and safer code by providing a way to attempt to retrieve a property value without having to explicitly check if each reference in its chain exists:
const user = {
name: 'Jim',
address: {
street: '123 Hochstraße',
city: 'Munich'
}
};
user?.address?.city // 'Munich'
user?.contacts?.email // undefined
In the above example, user?.address?.city
accesses the city
property of user.address
if user
and user.address
both exist. Otherwise, it returns undefined
. This approach avoids a common pitfall in JavaScript, where trying to access a property of undefined
or null
leads to a TypeError
:
user.contacts.email // Uncaught TypeError: Cannot read properties of undefined (reading 'email')
Before optional chaining, JavaScript developers had to use lengthy conditional logic to avoid such errors:
let email;
if (user && user.contacts) {
email = user.contacts.email;
} else {
email = 'Not specified';
}
email // 'Not specified'
Pipeline operator: |>
The pipeline operator (|>
) is intended to improve the readability of code that would otherwise be written with nested function calls. Essentially, it allows us to take the result of one expression and feed it into the next. This is particularly useful when we’re applying a series of transformations to a value:
const result = exclaim(capitalize(doubleSay('hello')));
console.log(result); //=> 'HELLO, HELLO!'
With the pipeline operator, we’re able rewrite this code like so:
const result = 'hello'
|> doubleSay
|> capitalize
|> exclaim;
console.log(result); //=> 'HELLO, HELLO!'
Be aware that, at the time of writing, the pipeline operator is at stage 2 of the ECMAScript proposal process, meaning it’s a draft and is undergoing further iteration and refinement.
Grouping operator: ()
The grouping operator (()
) in JavaScript is used to change the precedence of evaluation in expressions. This operator doesn’t perform any operations on its value, but it controls the order in which calculations are carried out within an expression.
For example, multiplication and division have higher precedence than addition and subtraction. This means that, in an expression such as 2 + 3 * 4
, the multiplication is done first, resulting in 2 + 12
, and then the addition is performed, giving a result of 14
.
If we want to change the order of operations, we can use the grouping operator. For example, if we want the addition to be done before the multiplication in the previous example, we could write (2 + 3) * 4
. In this case, the addition is performed first, resulting in 5 * 4
, and then the multiplication is performed, giving a result of 20.
The grouping operator allows us to ensure that operations are performed in the order we intend, which can be critical in more complex mathematical or logical expressions.
Conclusion
We’ve spent this article delving into the broad and sometimes complex world of JavaScript operators. These operators enable us to manipulate data, control program flow, and carry out complex computations.
Understanding these operators is not a mere academic exercise; it’s a practical skill that can enhance our ability to write and understand JavaScript.
Remember the confusing code snippet we started with? Let’s revisit that and see if it makes more sense now:
const x = 10, y = 20, z = 30;
console.log((x > y ? x : y) > z ? (x > y ? x : y) : z);
In plain English, this code is finding the maximum of three numbers, x
, y
, and z
.
It does this by using a combination of JavaScript’s ternary operator (? :
) and comparison operators (>
).
Here’s how it works:
- The expression
(x > y ? x : y)
checks whetherx
is greater thany
. - If
x
is greater thany
, it returnsx
; otherwise, it returnsy
. In other words, it’s getting the maximum ofx
andy
. - This result (the maximum of
x
andy
) is then compared toz
with the>
operator. - If the maximum of
x
andy
is greater thanz
, then second ternary(x > y ? x : y)
is evaluated. - In this ternary,
x
andy
are compared once again and the greater of the two is returned. - Otherwise, if
z
is greater than the maximum ofx
andy
, thenz
is the maximum of the three numbers, and it’s returned.
If you found this explanation confusing, that’s because it is. Nesting ternary operators like this isn’t very readable and the calculation could be better expressed using Math.max
:
Math.max(x, y, z)
// 30
Nonetheless, understanding how JavaScript operators work is like learning the grammar of a new language. It can be challenging at first, but once we’ve grasped the basics, we’ll be constructing complex sentences (or in our case, code) with ease.
Before I go, if you found this guide helpful and are looking to dive deeper into JavaScript, why not check out Learn to Code with JavaScript over on SitePoint Premium. This book is an ideal starting point for beginners, teaching not just JavaScript — the world’s most popular programming language — but also essential coding techniques that can be applied to other programming languages.
It’s a fun and easy-to-follow guide that will turn you from a novice to a confident coder in no time.
Happy coding!