What are operators?
Operators are one of the most vital concept in any hig-level programming language, including JavaScript.
Take the example of the addition operator, represented via the plus sign (+
). We all know what it does — it performs the addition operation on two given numbers.
The numbers involved in an addition operation can be also referred to as operands of the operation. An operand is basically just a value involved in an operation.
Operators in JavaScript are can be classified based on the number of operands they work with:
- Unary — operate with one operand.
- Binary — operate with two operands.
- Ternary — operate with three operands.
The bulk of operators in JavaScript are binary. Moreover, there is only one ternary operator, i.e. the conditional operator used to parse an expression conditionally.
In the following sections, we explore some of the most commonly-used operators in JavaScript.
Arithmetic operators
Across all high-level programming languages, we have the provision of arithmetic operators performing the most basic of operations such as addition, multiplication, exponentiation, and so on.
We already discovered the six arithmetic operators of JavaScript in the JavaScript Basics chapter.
Let's quickly review them all.
Operator | Symbol | Syntax | Purpose |
---|---|---|---|
Addition | + | a + b | Adds a and b . |
Subtraction | - | a - b | Subtracts b from a . |
Multiplication | * | a * b | Multiplies a with b . |
Division | / | a / b | Divides a by b . |
Exponentiation | ** | a ** b | Raises a to the power of b . |
Modulo | % | a % b | Returns the remainder when a is divided by b . |
The console snippet below demonstrates all of these operators:
5 + 5
9 - 1.5
5 * 5
5 / 2
5 ** 2
5 ** 3
25 ** 0.5
25 % 3
29 % 15
Arithmetic operators are pretty simple, aren't they?
String operators
This section is going to be extremely brief as there is only one string operator to consider in JavaScript — the concatenation operator.
To recall it, the concatenation operator (+
) is used to join together two strings into one single string.
Operator | Symbol | Syntax | Purpose |
---|---|---|---|
Concatenation | + | a + b | Concatenates a with b . |
We saw the concatenation operator for the very first time in JavaScript Basics, specifically in the Strings section. It is denoted using the same plus sign (+
) otherwise used to denote the addition operator in JavaScript.
By that means, JavaScript has to be able distinguish between arithmetic addition and string concatenation (as they're denoted the same way). And that's done with a very simple idea:
+
is a string, then it denotes string concatenation. Otherwise, it denotes arithmetic addition.If JavaScript determines that +
represents addition, it automatically coerces the operands into numbers before performing the addition.
By the same token, if +
is seen to be representing concatenation, the operands are automatically coerced into strings before performing the concatenation.
Let's take some quick examples:
'Hello' + ' World!'
'Hello World!'
'Hello' + 'World!'
'HelloWorld!'
'Hello' + ' ' + 'World!'
'Hello World!'
'Number: ' + 50
'Number: 50'
'Boolean ' + true
'Boolean: true'
Speaking of the last two statements, since 50
converts to the string '50'
, and true
converts to 'true'
, the expressions yield strings as if the non-string values were strings themselves, all thanks to JavaScript's automatic type coercion.
Concatenating with an empty string simply has no effect:
'' + ''
''
'Hello' + ''
'Hello'
'' + ' World!'
' World!'
Assignment operators
Being able to store data inside given identifiers in high-level programming languages is one of the most celebrated ideas. And at the heart of this idea lies the idea of assignment.
Assignment operators are used to assign given values to gien identifiers. Clearly, most basic assignment operators is the direct assignment operator, denoted as =
, that we've been using extensively uptil this point in this course.
Besides this, JavaScript defines many augmented assignment operators that are merely a combination of another operator with assignment.
Here's a list of all of them:
Operator | Symbol | Syntax | Purpose |
---|---|---|---|
Assignment | = | identifier = value | Assigns value to identifier . |
Addition-assignment (or concatenation-assignment) | += | i += v | Same as i = i + v . |
Subtraction-assignment | -= | i -= v | Same as i = i - v . |
Multiplication-assignment | *= | i *= v | Same as i = i * v . |
Division-assignment | /= | i /= v | Same as i = i / v . |
Exponentiation-assignment | **= | i **= v | Same as i = i ** v . |
Modulo-assignment | %= | i %= v | Same as i = i % v . |
Prefix-increment | ++ | ++i | Same as i += 1 . |
Prefix-decrement | -- | --i | Same as i -= 1 . |
Postfix-increment | ++ | i++ | Returns the current value of i and then performs i += 1 . |
Postfix-decrement | -- | i-- | Returns the current value of i and then performs i -= 1 . |
The augmented assignment operators are really handy when we want to update the value stored in a variable by performing an operation over it.
For instance, let's suppose that we have a variable x
and we want to increment it by 10
.
Surely, one way is to do this as follows, if we take the manual path of first adding x
to 10
and then assigning the result back to x
:
var x = 120;
x = x + 10;
console.log(x);
However, a much conciser way is to use the addition-assignment (+=
) operator, as follows:
var x = 120;
x += 10;
console.log(x);
The benefit of +=
, or any other augmented assignment operator, becomes even more evident when we have a very long identifier to modify.
Consider the following code where we are trying to increment the value of the lastYearInventoryCount
property of the firstReceivedItem
object by 100
using the manual approach:
var firstReceivedItem = {
/* Contains more properties here */
lastYearInventoryCount: 203,
}
firstReceivedItem.lastYearInventoryCount = firstReceivedItem.lastYearInventoryCount + 100;
console.log(firstReceivedItem.lastYearInventoryCount);
See how long line 6 is. First we have to refer to the property in the assignment context and then refer to it in the addition context.
Using +=
, we can extremely simplify this whole statement:
var firstReceivedItem = {
/* Contains more properties here */
lastYearInventoryCount: 203,
}
firstReceivedItem.lastYearInventoryCount += 100;
console.log(firstReceivedItem.lastYearInventoryCount);
Since +=
itself handles the addition, we don't have to refer to the long-winded identifier again.
Amazing.
Besides the augmented assignment operators, another handy collection of assignment operators is that of the prefix and postfix increment/decrement operators.
We have already witnessed the usage of the postfix increment (++
) operator in the JavaScript Control Flow chapter where we used it to construct a for
loop. Perhaps, the most common place of using postfix operators is in loops.
Generally speaking, whenever we want to increment (increase by 1) or decrement (decrease by 1) a variable in JavaScript, we do the following:
var x = 10;
x++; // Increment
x--; // Decrement
This is, more or less, like a convention. Plus, it's also simpler to type ++
and --
than += 1
(i.e. x += 1
) or -= 1
(i.e. x -= 1
), respectively.
The difference between postfix and prefix operators lies in when they increment or decrement a variable and what they return back.
Let's see what this means using a quick console inspection:
var x = 10;
The expression x++
returns 10
which is exactly the value that we initialize x
with in the very first statement. Seeing 10
, we might feel as if x
hasn't been incremented. Likewise, we inspect x
again to see its value. Now, it turns out to be 11
, confirming that yes it has been incremented.
As this examples shows, the postfix increment (++
) operator first returns back the given variable and then afterwards, increments it. The same applies to the postfix decrement (--
) operator.
In contrast, a prefix increment operator works differently. In particular:
Once again, let's inspect this in the console, using the same example as shown above:
var x = 10;
The expression ++x
returns back 11
which is clearly the incremented value of x
. Inspecting x
again, we see that its value remains 11
, thereby confirming that it has been done incrementing.
Now as far as the question goes as to when to use prefix increment/decrement vs. postfix increment/decrement, it has quite an obvious answer.
When to use postfix increment/decrement and when to use prefix increment/decrement?
If all what we want to do is increment or decrement a variable, as a standalone statement, there's really not much of a difference if we use a postfix or a prefix operator.
The following two snippets aren't much different from one another:
var x = 10;
x++; // Postfix
var x = 10;
++x; // Prefix
The increment happens as a standalone statement, and so it doesn't matter whether the expression resolves down with the incremented value of x
or the original value of x
.
Using a prefix operator is really handy when we want to provide a variable's incremented value to another variable or function without having to type a separate assignment statement for it.
For instance, suppose that we want to store the incremented value of x
to the variable incrementedX
and, at the same time, also make sure that x
itself is incremented.
One way to do so is as follows:
/* Suppose x has been defined */
x++;
var incrementedX = x;
Clearly, not any difficult to read or type.
But still, there's an even more simpler way, thanks to the prefix increment operator:
/* Suppose x has been defined */
var incrementedX = ++x;
++x
makes sure that x
gets incremented before resolving down to the resulting value. This value then gets assigned to incrementedX
.
Without any doubt, this approach is much more elegant than having to type a separate statement to increment x
.
Relational operators
Relational operators are used to test whether two given values are related to one another in a particular way. A relational operator evaluates down to a Boolean value to specify whether the relationship holds or not.
Once again, we've already seen a couple of relational operators from the previous chapters; specifically, the less-than-or-equal-to (<=
) and the identity (===
) operators.
Listed below are the relational operators in JavaScript:
Operator | Symbol | Syntax | Purpose |
---|---|---|---|
Equality | == | a == b | Checks whether a and b are equal. |
Identity | === | a === b | Checks whether a and b are identical. |
Non-equality | != | a != b | Negates the result of a == b . |
Non-identity | !== | a !== b | Negates the result of a === b . |
Less-than | < | a < b | Checks whether a is less than b . |
Less-than-equal-to | <= | a <= b | Checks whether a is less than or equal to b . |
Greater-than | > | a > b | Checks whether a is greater than b . |
Greater-than-equal-to | >= | a >= b | Checks whether a is greater than or equal to b . |
in | - | key in obj | Checks whether the key key exists in the object obj or any of its prototypes. |
instanceof | - | obj instanceof Fn | Checks whether the object obj is an instance of the constructor function Fn or any of its prototypes. |
We'll discover the last two of these — in
and instanceof
— in the JavaScript Objects unit once we understand about property enumeration, constructor functions and prototypes.
Let's quickly review the rest of the relational operators.
First, we'll consider the equality and identity operators along with their negated versions:
5 == 5
5 == '5'
5 === 5
5 === '5'
5 != 5
5 != '5'
5 !== 5
5 !== '5'
And now we'll consider the inequality operators:
5 < 10
5 < 5
5 <= 5
5 > 10
15 > 10
10 >= 10
Logical operators
Logical operators are used to operate on Boolean values. Except for the logical NOT (!
) operator, as we shall see below, all logical operators combine the values of two Booleans together.
Logical operators are extensively used in conditional programming, i.e. executing code based on the outcome of given conditions. We'll be using them frequently once we finally get done with our JavaScript Conditions unit.
The whole idea behind logical operators in JavaScript, and other programming languages, stems directly from the idea of logical operators in propositional calculus.
Following are the three logical operators of JavaScript:
Operator | Symbol | Syntax | Purpose |
---|---|---|---|
Logical NOT | ! | !a | Negates the truth value of a . |
Logical OR | || | a || b | Yields a if it's truthy, or else yields b . |
Logical AND | && | a && b | Yields a if it's falsey, or else yields b . |
Let's see each one of these in action.
We'll start with the logical NOT (!
) operator.
Logical NOT (!
)
As you can see above, the logical NOT (!
) operator is a unary operator that serves to negate the truth value of its operand. In other words, if the operand is true
, we get false
and, similarly, if it's false
, we get true
.
Consider the following example:
!true
!false
Technically, it isn't required for the operand of the logical NOT operator to be a Boolean — it can be literally any value.
JavaScript is able to apply logical operators on non-Boolean values by first converting them to Booleans and then performing the respective operations.
In this regard, we often use the term 'truthy' to refer to values that get converted to the Boolean true
and the term 'falsey' to refer to values that get converted to false
. JavaScript defines some extremely simple rules to determine which values are truthy and which are not.
For example, all strings, except for empty string, are truthy. Likewise, !''
will return true
as ''
converts to the Boolean false
.
!''
We'll see these rules in detail in the chapter JavaScript Conditions — Booleans.
Now, let's see the logical OR (||
) operator.
Logical OR (||
)
From a logical point of view, the logical OR operator (||
) takes two Booleans, and returns true
if either one of them is true
, or else returns false
.
This can be seen in the snippet below:
true || true
true || false
false || true
false || false
However, in JavaScript, there's more to the logical OR operator. As with the logical NOT operator, it can operate with non-Boolean values, converting them to Booleans before proceeding.
In that manner, we can define logical OR more precisely as follows: it takes two arbitrary values and returns the first one if it's truthy, or else returns the second value.
Once again, this mandates a discussion on what JavaScript considers truthy and what not, which we'll cover later on in this course.
But still, let's try it with the same idea of strings that we employed above with the logical NOT operator. That is, an empty string is falsey whereas all other strings are truthy.
'' || 'Hello'
'Hello' || ''
'Hello' || 'World!'
'' || ''
To make intuition of this snippet, convert each string to a Boolean and then apply the ||
operator over each expression to determine which string would it end up with.
If you're somehow having a hard time understanding this, don't worry as we'll understand this in detail in JavaScript Conditions — Booleans.
Anyways, it's time to talk about the logical AND (&&
) operator.
Logical AND (&&
)
Logically, &&
takes two Booleans and returns true
if both of them are true
, or else returns false
.
true && true
true && false
false && true
false && false
But speaking technically, it takes two arbitary values and returns the first one if it's falsey, or else returns the second value.
Let's demonstrate this with the help of strings:
'' && 'Hello'
'Hello' && ''
'Hello' && 'World!'
'' && ''
As before, to make intuition of this snippet, convert each string to a Boolean and then apply the &&
operator over each expression to determine which string would it boil down to.
Moving on, one thing you'll hear frequently while using the logical OR (||
) and the logical AND (&&
) operators is that they are both short-circuit operators.
||
and &&
are short-circuit operators
So what does this mean?
Well, being short-circuit operators means that both &&
and ||
first evaluate the left operand and if that evaluation suggests that there's no point of evaluating the right operand, then they simply just don't do it.
In other words, they literally 'short-circuit' their evaluation of a given expression.
- The logical OR (
||
) operator only evaluates the right operand if the left operand is falsey. - On the other hand, the logical AND (
&&
) operator only evaluates the right operand if the left one is truthy.
We can actually witness this short-circuit behavior by creating a function that's used in a logical expression involving ||
and/or &&
. An example follows.
With the following function defined,
function booleanTrue() {
console.log('Inside the function');
return true;
}
that logs its invocation and merely returns back true
, the following logical expressions don't invoke booleanTrue()
, thanks to the short-circuit behavior of ||
and &&
:
true || booleanTrue()
false && booleanTrue()
How do we know that for sure? Well, because if booleanTrue()
was called, there would've ultimately been a log displayed. Yet, we don't see any log, which confirms that booleanValue()
isn't executed.
The following expressions, however, do invoke booleanTrue()
:
false || booleanTrue()
true && booleanTrue()
This behavior of short-circuiting can have some amazing consequences in code as we shall learn in the JavaScript Conditions unit.
Nullish coalescing operator
The nullish coalescing operator, denoted as ??
, is a very neat shorthand for the logical OR (||
) operator along with a check for null
ish values.
In particular, ??
evaluates its left operand and returns it if it's not null
or undefined
, or else returns its right operand (whatever that is).
Let's turn to the console to see how ??
works.
In each of the following expressions, the left operand of ??
is not null
(or undefined
) and so the operand is merely returned back in the operation:
10 ?? 100
10
'' ?? false
''
false ?? 'Hello World!'
false
However, following we have expressions where the left operand is null
and likewise we get nullish coalescing performed:
null ?? 100
100
null ?? false
false
undefined ?? 'Hello World!'
'Hello World!'
undefined ?? ''
''
Surprisingly enough, it's syntactically invalid to use the logical OR (||
) or the logical AND (&&
) operator along with the nullish coalescing (??
) operator, without a pair of parentheses (()
).
Consider the following code:
var x = null;
var y = x ?? 'Amazing' || false;
console.log(y);
We get an error thrown as we're trying to use ||
along with the ??
operator, which is an ambiguous combination.
If we really want to use it, we ought to use a pair of parentheses (()
) to group an operation. This is demonstrated as follows:
var x = null;
var y = x ?? ('Amazing' || false);
console.log(y);