Course: JavaScript

Progress (0%)

JavaScript Operators

Chapter 11 37 mins

Learning outcomes:

  1. What are operators
  2. Unary, binary and ternary operators
  3. Arithmetic operators (+, -, *, /, **, %)
  4. String operators (+)
  5. Relational operators (==, ===, !=, !==, <, <=, >, >=)
  6. Logical operators (!, ||, &&)
  7. The nullish coalescing operator (??)
  8. Assignment operators

What are operators?

Operators are one of the most vital concept in any hig-level programming language, including JavaScript.

An operator is a symbol or keyword representing an operation, i.e. a function.

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:

  1. Unary — operate with one operand.
  2. Binary — operate with two operands.
  3. 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.

OperatorSymbolSyntaxPurpose
Addition+a + bAdds a and b.
Subtraction-a - bSubtracts b from a.
Multiplication*a * bMultiplies a with b.
Division/a / bDivides a by b.
Exponentiation**a ** bRaises a to the power of b.
Modulo%a % bReturns the remainder when a is divided by b.

The console snippet below demonstrates all of these operators:

5 + 5
10
9 - 1.5
7.5
5 * 5
25
5 / 2
2.5
5 ** 2
25
5 ** 3
125
25 ** 0.5
5
25 % 3
1
29 % 15
14

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.

OperatorSymbolSyntaxPurpose
Concatenation+a + bConcatenates 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.

In some languages, such as PHP, the arithmetic addition and the string concatenation operators are denoted differently. And similarly, in some languages, such as Python, just like JavaScript, they are denoted in the same way.

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:

If either of the operands of + 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.

In some languages, such as Python, it's invalid to concatenate strings with non-string values. If we wish to do so, we have to first manually convert the non-string values into strings, and then perform the concatenation.

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:

OperatorSymbolSyntaxPurpose
Assignment=identifier = valueAssigns value to identifier.
Addition-assignment (or concatenation-assignment)+=i += vSame as i = i + v.
Subtraction-assignment-=i -= vSame as i = i - v.
Multiplication-assignment*=i *= vSame as i = i * v.
Division-assignment/=i /= vSame as i = i / v.
Exponentiation-assignment**=i **= vSame as i = i ** v.
Modulo-assignment%=i %= vSame as i = i % v.
Prefix-increment++++iSame as i += 1.
Prefix-decrement----iSame 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);
130

However, a much conciser way is to use the addition-assignment (+=) operator, as follows:

var x = 120;
x += 10;

console.log(x);
130

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);
303

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);
303

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.

A postfix-increment, or postfix-decrement operator, first returns back the original variable's value and then increments or decrements it, respectively.

Let's see what this means using a quick console inspection:

var x = 10;
undefined
x++
10
x
11

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:

A prefix-increment, or prefix-decrement operator, first increments or decrements a variable, respectively, and then returns it back (holding the new value).

Once again, let's inspect this in the console, using the same example as shown above:

var x = 10;
undefined
++x
11
x
11

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:

OperatorSymbolSyntaxPurpose
Equality==a == bChecks whether a and b are equal.
Identity===a === bChecks whether a and b are identical.
Non-equality!=a != bNegates the result of a == b.
Non-identity!==a !== bNegates the result of a === b.
Less-than<a < bChecks whether a is less than b.
Less-than-equal-to<=a <= bChecks whether a is less than or equal to b.
Greater-than>a > bChecks whether a is greater than b.
Greater-than-equal-to>=a >= bChecks whether a is greater than or equal to b.
in-key in objChecks whether the key key exists in the object obj or any of its prototypes.
instanceof-obj instanceof FnChecks 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
true
5 == '5'
true
5 === 5
true
5 === '5'
false
5 != 5
false
5 != '5'
false
5 !== 5
false
5 !== '5'
true

And now we'll consider the inequality operators:

5 < 10
true
5 < 5
false
5 <= 5
true
5 > 10
false
15 > 10
true
10 >= 10
true

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.

Learn more about propositional operators in the chapter Propositional Logic — Logical Operators of our course on Elementary Logic

Following are the three logical operators of JavaScript:

OperatorSymbolSyntaxPurpose
Logical NOT!!aNegates the truth value of a.
Logical OR||a || bYields a if it's truthy, or else yields b.
Logical AND&&a && bYields 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
!false
true

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.

!''
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
true || false
true
false || true
true
false || 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' || ''
'Hello'
'Hello' || 'World!'
'Hello'
'' || ''
''

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
true && false
false
false && true
false
false && 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!'
'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()
true
false && booleanTrue()
false

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()
Inside the function true
true && booleanTrue()
Inside the function true

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 nullish 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);
Amazing

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage