Operators
Expressions and operators
Operators are part of an expression. An expression is a piece of code that evaluates to a value. Expressions are usually part of statements.
For instance; let a = 2;
is a statement in which
a = 2
is an expression and in which =
is an operator.
The expression a = 2
is an assignment, but the expression itself also evaluates to a value:
assignments have a return value (later more about this):
let a;
console.log(a = 2); // logs: 2 // logs the assignments' return value.
An operator is a sign or keyword mostly relating two operands. JavaScript has multiple types of operators:
- Assignment operators
- Comparison operators
- Arithmetic operators
- Logical operators
- Bitwise operators
- and some other types: string (concatenation), conditional, comma, unary and relational operators.
let counter = 0; // operator: =
while (counter < 10) { // operator: <
if (counter % 2 === 0) { // operators: % and ===
console.log(counter + " is even"); // operator: +
} else {
console.log(counter + " is odd"); // operator: +
}
counter += 1; // operator: +=
}
Assignment operators
A value can be assigned to a variable or constant by using an assignment operator.
The initial assignment must always use the "equal to" sign (=
) as operator, e.g. let a = b;
.
In this context the "equal to" sign means "a
gets assigned the value b
"
as opposed to its meaning in a mathematical context: "a
equals b
".
Comparison operators do provide "equal to" operators as explained below.
All other assignment operators are compound assignment operators (like x += y
).
They are shorthand operators for assigning a variable its previous value
which has an arithmetic operation performed on (see arithmetic operators below).
The (compound) assignment operations are listed in the following table:
Name | Shorthand operator | Explanation |
---|---|---|
Assignment | x = y |
|
Addition assignment | x += y |
Same as: x = x + y |
Subtraction assignment | x -= y |
Same as: x = x - y |
Multiplication assignment | x *= y |
Same as: x = x * y |
Division assignment | x /= y |
Same as: x = x / y |
Remainder assignment | x %= y |
Same as: x = x % y |
Exponentiation assignment | x **= y |
Same as: x = x ** y |
Increment assignment | x++ and ++x |
As a prefix operator (++x ) it returns the value of its operand after adding 1.As a postfix operator ( x++ ) it returns the value of its operand before adding 1.If x is 3 then:++x sets x to 4 and returns 4 (same as x += 1 ).x++ returns 3 and, only then, sets x to 4.
|
Decrement assignment | x-- and --x |
As a prefix operator (--x ) it returns the value of its operand after subtracting 1.As a postfix operator ( x-- ) it returns the value of its operand before subtracting 1.If x is 3, then:--x sets x to 2 and returns 2 (same as x -= 1 ).x-- returns 3 and, only then, sets x to 2.
|
Like most expressions in JS, assignments have a return value.
The return value matches the expression to the right of the =
-sign.
let varA = 0,
varB = 10;
console.log(varA = varB); // logs: 10 // it logs the return value varB (and varA is assigned the value 10)
console.log(varA += varB); // logs: 20 // varA = varA + varB thus it returns: varA + varB
console.log(varA); // logs: 20
console.log(varB **= 3); // logs: 1000 // varB = varB ** 3 (varB = 10^3).
The increment and decrement assignments return as mentioned in table 1.
let varA = 0;
console.log(++varA); // logs: 1
console.log(varA); // logs: 1
varA = 0;
console.log(varA++); // logs: 0
console.log(varA); // logs: 1
let varB = 10;
console.log(--varB); // logs: 9
console.log(varB); // logs: 9
varB = 10;
console.log(varB--); // logs: 10
console.log(varB); // logs: 9
Compound assignment operators are often used in conjunction with loops.
In the next code fragment i += 0.1
is the same as i = i + 0.1
, which means
that the "new" i
gets assigned the "old" i
plus 0.1.
Thus i
increases an increment of 0.1 every iteration in the while-loop.
let i = 0;
while (i < 10) {
console.log(i);
i += 0.1;
}
BTW: The seemingly inconsistent precision of the increments of 0.1 in the result is due to the properties of floating point numbers.
Comparison operators
A comparison operator compares both operands and returns a logical value (true
or false
)
based on whether the comparison is true or not. For example 3 > 2
returns true
.
Comparison operators are often used in conditional statements and loops.
Operator | Description |
---|---|
a == b |
Equal: returns true if the operands are equal. |
a != b |
Not equal: returns true if the operands are not equal. |
a === b |
Strict equal: returns true if the operands are equal and of the same data type. |
a !== b |
Strict not equal: returns true if the operands are of the same data type but not equal, or are of different data type. |
a > b |
Greater than: returns true if a is greater than b . |
a >= b |
Greater than or equal: returns true if a is greater than or equal to b . |
a < b |
Less than: returns true if a is less than b . |
a <= b |
Less than or equal: returns true if a is less than or equal to b . |
Values are of some data type, e.g. a number, a string (text), a boolean (true
or false
), an object.
Data types will be covered in detail later in this tutorial.
Strict comparison operations (===
and !==
) always return false
when the two compared operands are of different data types.
With all the other comparison operators
JavaScript will automatically convert operands of different types to an appropriate type for the comparison.
This is called type coercion. How JS executes this will be explained
in more detail in the chapters
type coercion and
falsy & truthy.
Greater than (or equal) and less than (or equal) operators generally coerce operands of different type to numbers and compare them numerically.
If both operands are strings, then they are compared alphabetically.
let name = "Beth"; // A value enclosed in single or double quotation marks indicates a string value.
console.log('beth' == name); // logs: false // case sensitive!
console.log(2 == 2); // logs: true
console.log(2 != 5); // logs: true
console.log("313" == 313); // logs: true // The string "313" is coerced to number 313.
console.log("313" === 313); // logs: false // Non-matching data types.
console.log(false != 0); // logs: false // Boolean false is coerced to 0, which IS equal to 0.
console.log(false !== 0); // logs: true // Non-matching data types: they are indeed not strict equal.
console.log(10 > 2); // logs: true
console.log(7 >= 7); // logs: true
console.log('Alice' < name); // logs: true // compared alphabetically (case sensitive!).
console.log('2' < '123'); // logs: false // compared alphabetically 2 is greater than 1.
console.log(true < 2); // logs: true // "true" automatically converted to 1, which is less than 2.
BTW: A string literal is signified by placing the string of whatever characters within quotation marks.
Literals 'a'
and "a"
both signify the same string.
Arithmetic operators
Arithmetic operators are used in conjunction with numerical operands where the operation returns a single numerical value.
Operator | Description | Example |
---|---|---|
a + b |
Addition: returns the sum of the two operands. | 2 + 3 returns 5. |
a - b |
Subtraction: returns the result of a minus b . |
8 - 3 returns 5. |
a * b |
Multiplication: returns the product of the two operands. | 3 * 5 returns 15. |
a / b |
Division: returns the result of a divided by b . |
6 / 2 returns 3. |
a ** b |
Exponentiation: returns the result of a raised to the power of b . |
2 ** 3 returns 8.10 ** -1 returns 0.1.
|
a % b |
Remainder (modulo operation): returns the integer remainder of a divided by b . |
12 % 5 returns 2. |
-a |
Negation. Returns the negation of its operand. |
If x is 3 , then -x returns -3.If x is -3 , then -x returns 3.
|
+a |
Unary plus. Attempts to convert the operand to a number, if it is not already. | See explanation below |
JavaScript also has a built-in object with properties and methods for mathematical constants and functions.
This object is Math
.
For instance, Math.pow(3,2)
returns 9 (3 to the exponent power 2).
let myVar;
console.log(Math.pow(3,2) === 3 ** 2); // logs: true
console.log(myVar = 2 - 5); // logs: -3
console.log(-myVar); // logs: 3
console.log(--3); // SyntaxError: invalid increment/decrement operand. // Assigning a value to a value is not possible
console.log(-(-3)); // logs: 3
console.log(7--3); // SyntaxError: invalid increment/decrement operand.
console.log(7-(-3) === 10); // logs: true
console.log(2/0 === Infinity); // logs: true
console.log(9**(1/2)); // logs: 3 // √9 = 3.
console.log(9**(1/2) === Math.sqrt(9)); // logs: true
When operands are not numbers, JS "type coerces" them to a number.
More about this in chapter type coercion.
An exception is the addition operator (a + b
) performed on string operands. In that case the separate strings
are concatenated to a single string. This also holds for the addition assignment operator, since a += b
equals a = a + b
.
console.log("Hello" + " you!"); // logs: "Hello you!"
let str = "Hello";
console.log(str += " you!"); // logs: "Hello you!"
console.log(str += " How ya doin'?"); // logs: "Hello you! How ya doin'?"
console.log(2 + 3); // logs: 5
console.log("2" + 3); // logs: "23" // string concatenation
BTW: The addition operator concatenates strings if at least one of both operands is a string.
With the unary plus operator (+a
) you can explicitly convert operands of any data type to numbers.
console.log(+-3); // logs: -3.
console.log(+3); // logs: 3.
console.log(++3); // logs: SyntaxError: invalid increment/decrement operand.
console.log(+"3"); // logs: 3.
console.log(+true); // logs: 1.
console.log(+false); // logs: 0.
console.log(+"2" + 3); // logs: 5
Logical operators
Logical operators (aka logical connectives) typically take operands with Boolean
(i.e. logical) values true
or false
and return a Boolean value.
Operator | Description |
---|---|
a && b |
Logical AND (logical conjunction). Returns true if both operands are true ; otherwise, it returns false . |
a || b |
Logical OR (logical disjunction). Returns true if either operand is true ; otherwise, if both are false , it returns false . |
a ?? b |
Nullish coalescing operator. Returns b if a is null or undefined ; otherwise it returns a .
Technically not a logical operator. Will be explained below.
|
!a |
Logical NOT (logical negation). Returns false if its single operand is true ; otherwise, if operand false , it returns true . |
let x = 3,
y = 11,
z = true;
console.log( z && (y > 10) ); // logs: true // ⇐ true && true
console.log( (x !== 4) && (!(y === 11)) ); // logs: false // ⇐ true && false
console.log( (x >= 3) || (y === 5) ); // logs: true // ⇐ true || false
console.log( (x === 5) || (y === 5) ); // logs: false // ⇐ false || false
console.log( !(x !== y) ); // logs: false // ⇐ not true
Operand values do not have to be precisely false
or true
.
They may also be falsy or truthy. Falsy values are for instance 0
, ""
(empty string), null
and undefined
.
All values that are not falsy are truthy.
Falsy values are automatically converted to false
and thruthy values are automatically converted to true
.
More about this in chapter
falsy & truthy.
Short-circuiting
Above is stated that logical operations return a Boolean value true
or false
. This is actually not accurate.
The next two functions do the same as the &&
and ||
operators.
Note that only expr1
is evaluated (expr2
does not take effect in the evaluation), which is called short-circuiting.
So, logical operations may also return a falsy or truthy value.
// &&: Return expr1 if expr1 can be converted to false; otherwise, return expr2.
function logicalAND(expr1, expr2) {
if (!expr1) { return expr1; }
else { return expr2; }
}
// ||: Return expr1 if expr1 can be converted to true; otherwise, return expr2.
function logicalOR(expr1, expr2) {
if (expr1) { return expr1; }
else { return expr2; }
}
console.log( logicalAND("2" == 2, '7' >= 7) ); // logs: true // Same as: ("2" == 2) && ('7' >= 7).
console.log( logicalOR(2 === 3, 'John') ); // logs: "John" // Same as: 2 === 3 || 'John'.
console.log( logicalOR('', 'Jane') ); // logs: "Jane" // Same as: "" || 'Jane'. "" is a falsy value.
console.log( logicalOR('John', 'Jane') ); // logs: "John" // Same as: 'John' || 'Jane'. 'John' is a truthy value.
console.log( logicalAND(0, 2 === 2) ); // logs: 0 // Same as: 0 && 2 === 2. 0 is a falsy value.
console.log( logicalOR(1, false) ); // logs: 1 // Same as: 1 || false. 1 is a truthy value.
Nullish coalescing operator
As an alternative to the logical OR (||
)
you can use the
nullish coalescing operator
(??
).
It only returns the second operand if the first one is nullish, i.e. either null
or undefined
.
The logical OR (||
) returns the right-hand side operand if the left operand is any falsy value,
not only if null
or undefined
.
Next function does the same as the ??
operator.
Also the nullish coalescing operator evaluates short-circuit;
the right-hand side operand does not take effect in the evaluation.
// ??: Return expr1 if expr1 is NOT null or undefined; otherwise, return expr2.
function nullishCoalescing(expr1, expr2) {
if (expr1 != null) { return expr1; }
else { return expr2; }
}
console.log( nullishCoalescing(null, 'Hello') ); // logs: "Hello" // Same as: null ?? 'Hello'.
console.log( nullishCoalescing(undefined, 'Hello') ); // logs: "Hello" // Same as: undefined ?? 'Hello'.
console.log( nullishCoalescing(false, 'Hello') ); // logs: false // Same as: false ?? 'Hello'.
console.log( nullishCoalescing("", 'Hello') ); // logs: "" // Same as: "" ?? 'Hello'.
This short-circuiting is often used to assign a default value to a variable or constant.
let updateText, updateNumber, currentText, currentNumber;
const defaultText = "John/Jane Doe",
defaultNumber = 1;
updateText = null;
currentText = updateText || defaultText;
console.log(currentText); // logs: "John/Jane Doe"
updateNumber = 2;
currentNumber = updateNumber || defaultNumber;
console.log(currentNumber); // logs: 2
// 0 may be a valid value in this case, but 0 is falsy and thus defaultNumber is assigned
updateNumber = 0;
currentNumber = updateNumber || defaultNumber;
console.log(currentNumber); // logs: 1
// The nullish coalescing operator avoids the above pitfall
updateNumber = 0;
currentNumber = updateNumber ?? defaultNumber;
console.log(currentNumber); // logs: 0
updateText = "";
currentText = updateText ?? defaultText;
console.log(currentText); // logs: "" // it does NOT log defaultText!
Compound assignments
Logical operators can also be compounded with assignment operator =
.
The short-circuit evaluation of the logical operator results in an assignment only if the left-hand side operand is
truthy, falsy or nullish, depending on the logical operator.
Name | Compound assignment |
Short for: | Meaning |
---|---|---|---|
Logical AND assignment | a &&= b |
a && (a = b) |
Only assigns if a is truthy. |
Logical OR assignment | a ||= b |
a || (a = b) |
Only assigns if a is falsy. |
Logical nullish assignment | a ??= b |
a ?? (a = b) |
Only assigns if a is nullish. |
Generally the return value of an assignment matches the expression to the right of the =
-sign.
However, the return values of the logical compound assignments above
are those of the logical operations without the assignment.
For example, the return value of a &&= b
equals the return value of a && b
.
let a = 1, b = "hello";
console.log(a ||= b); // logs: 1 // logs the return value of a || b.
These compound assignments are especially useful for setting default content.
let currentNumber;
const defaultNumber = 10;
currentNumber = 0; // is falsy
console.log(currentNumber ||= defaultNumber); // logs: 10 // currentNumber was assigned the value of defaultNumber
currentNumber = 0; // is NOT nullish
console.log(currentNumber ??= defaultNumber); // logs: 0 // no assignment occurred
<body>
<label>Your name: <input id="inputName" type="text" /></label>
<button id="myButton">OK</button>
<p id="greeting">Hello <span>You</span>!</p>
<script>
'use strict';
const inputName = document.querySelector('#inputName'); // inputName.value will be the STRING that the user typed in the input field (i.e. the name).
document.querySelector('#myButton').addEventListener('click', function(){
inputName.value ||= 'John/Jane Doe'; // if no name is filled in (empty string), inputName.value gets reassigned the default value "John/Jane Doe".
document.querySelector('#greeting > span').textContent = inputName.value;
});
</script>
</body>
Hello You!