JavaScript programs are combinations of operators, expressions, and statements. They let us manipulate and change data, make calculations, compare values, and do much more.
An expression is code that evaluates to a value. Example expressions include things like 3 + x
and a*b
. A statement is code that does an action. For example, loops and conditional code like if
and switch
are statements. Wherever you can write statements, you can also write expressions, but the reverse is not true.
Operator Precedence
Operators are special symbols that let you combine and compute values. They are also in all JavaScript expressions. There are many of them, and the order of them matters. This is why we have operator precedence rules in JavaScript.
Below is the full list of operators in JavaScript, from highest to lowest precedence. The higher ones are evaluated before the lower ones. The following list is ordered from precedence 20, which is the highest, to precedence 1, which is the lowest.
Most operators also have associativity, which has the same meaning as in math. It means that when you group the same results done repeatedly with a given operator in whatever way you want, you get the same result, for example when you multiply three numbers, (a*b)*c === a*(b*c)
.
- grouping operator:
(...)
, precedence 20, example:(a+b)
- member access:
...,...
, precedence 19, associative left to right, example:a.b
- computed member access (accessing object properties with a string as the key)
...[...]
, precedence 19, associative left to right, example:a['b']
new
operator with arguments list,new ... (...)
, precedence 19, example:new Bird('small')
- optional chaining:
?.
, precedence 19, associative left to right, example:a?.b
new
operator without arguments list:new …
, associative right to left, example:new Bird
- postfix increment:
…++
, precedence 17, example:x++
- postfix decrement:
…--
, precedence 17, example:x--
typeof
operator:typeof …
, precedence 16, associative right-to-left, example:typeof x
- logical NOT:
!...
, precedence 16, associative right-to-left, example:!x
- bitwise NOT:
~...
, precedence 16, associative right-to-left, example:~x
- unary plus:
+...
, precedence 16, associative right-to-left, example:+x
- unary negation:
-...
, precedence 16, associative right-to-left, example:-x
- prefix increment:
++..
, precedence 16, associative right-to-left, example:++x
- prefix decrement
--..
, precedence 16, associative right-to-left, example:--x
void
operator:void …
, precedence 16, associative right-to-left ,example:void(0)
delete
operator:delete...
, precedence 16, associative right-to-left ,example:delete a.b
await
operator:await...
, precedence 16, associative right-to-left ,example:await promise
- exponentiation :
...**...
, precedence 15, associative right-to-left ,example:a**b
- multiplication:
...*...
, precedence 14, associative left-to-right , example:a*b
- division:
.../...
, precedence 14, associative left-to-right, example:a/b
- remainder:
...%...
, precedence 14, associative left-to-right, example:a % b
- addition:
...+...
, precendence 13, associative left-to-right, example:a + b
- subtraction:
...-...
, precedence 13, associative left-to-right, example:a — b
- bitwise left shift:
...<<...
, precedence 12, associative left-to-right, example:a << b
- bitwise right shift:
...>>...
, precedence 12, associative left-to-right, example:a >> b
- bitwise unsigned right shift:
...>>>...
, precedence 12, associative left-to-right, example:a >>> b
- less than:
...<...
, precedence 11, , associative left-to-right, example:a < b
- less than or equal:
...<=...
, precedence 11, , associative left-to-right, example:a <= b
- greater than:
...>...
, precedence 11, , associative left-to-right, example:a >b
- greater than or equal to:
...>=...
, precedence 11, , associative left-to-right, example:a >= b
in
:...in...
, precedence 11, , associative left-to-right, example:a in b
instanceof
:...instanceof...
, precedence 11, associative left-to-right, example:a instance Bird
- equality:
...==...
, precedence 10, associative left-to-right, example:a == b
- inequality:
...!=...
, precedence 10, , associative left-to-right, example:a != b
- strict equality:
...===...
, precedence 10, associative left-to-right, example:a === b
- strict inequality:
...!==...
, precedence 10, associative left-to-right, example:a !== b
- bitwise AND:
...&...
, precedence 9, associative left-to-right, example:a & b
- bitwise XOR:
...^...
, precedence 8, associative left-to-right, example:a ^ b
- bitwise OR:
... | ...
, precedence 7, associative left-to-right, example:a | b
- logical AND:
...&&...
, precedence 6, associative left-to-right, example:a && b
- logical OR:
...||...
, precedence 5, associative left-to-right, example:a || b
- conditional operator:
… ? … : …
, precedence 4, associative right-to-left, example:a ? b : c
- all assignment operators
… = …
,… += …
,… -= …
,… **= …
,… *= …
,… /= …
,… %= …
,… <<= …
,… >>= …
,… >>>= …
,… &= …
,… ^= …
,… |= …
, precedence 3, associative right-to-left, examples:a = b
,a += b
,a -= b
,a *= b
,a /= b
,a %= b
yield
andyield*
operator, precedence 2, associative right-to-left, examples:yield x
,yield* x
- comma / sequence operator:
...,...
, precedence 1, associative left-to-right, example:a, b
Parentheses
Parentheses allow us to group together expressions that we want to be evaluated before anything else. It also makes reading the close a lot more clear than without grouping expressions in parentheses.
To group expressions in parenthesis, we write:
let a = (1 + 2) * (1 / 2); // 1.5
let a = (1 + (2 * 1)) / 1; // 3
let a = ((1 + 2) *1) / 2; // 1.5
let a = 1 + ((2 * 1) / 2); // result: 2
Meaning of Operators
As we can see from the list above, JavaScript has lots of operators.
Assignment operators
Assignment operators are used to give a variable a value. It reads from right to left. For example, let a = 1
sets the value of variable a
to 1. We can also have more than one assignment operator in one line by writing: let a = b = c = 1
. This way, we assign the value of a
, b
, and c
to the value 1. Again, we read the expression from right to left. First c
is assigned the value 1, then b
is assigned c
, which has the value 1, then finally, a
is assigned the value of b
, which is 1.
All assignment operators can be chained in one line like we did above. Suppose we write:
let b = 1;
let a = b += c = 1;
We first set 1 as the value of b
in the first line. Then in the second line, we set the value of c
to 1. Then we increment the value of b
by c
, which is 1, and b
becomes 2, which is then assigned to a
, which also gets the value of 2.
Comparison operators
Comparison operators are for comparing the values of objects.
We have the following comparison operators:
- Equality operator (
==
), which compares only the content of objects without the type:==
. For example,3 == 3
would betrue
, and3 == '3'
would also betrue
. - Inequality operator (
!=
), which also compares only the content of objects without the type. For example,1 != 1
would befalse
, and1 != '1'
would also befalse
. - Strict equality operator (
===
), which compares both the content and the type of objects for equality. For example,1 === “1”
would befalse
, and1 === 1
would betrue
. - Strict inequality (
!==
), which compares both the content and the type of object for inequality. For example,3 !== “3”
would betrue
, and3 !== 3
would befalse
. - Greater than operator (
>
), which compares the value of two numbers and evaluates totrue
if the number left of the greater than sign is bigger than the right one. For example,7 > 2
would betrue
. - Greater than or equal to operator (
>=
), which compares the value of two numbers and evaluates totrue
if the number left of the greater than sign is bigger than or equal to the right one. For example,1 >= 1
would betrue
. - Less than operator (
<
), compares the value of two numbers and evaluates totrue
if the number left of the greater than sign is smaller than the right one. For example,1< 2
would betrue
. - Less than or equal to operator (
<=
), which compares the value of two numbers and evaluates totrue
if the number left of the greater than sign is smaller than or equal to the right one. For example,1 <= 1
would betrue
.
Arithmetic operators
Arithmetic operators, as the name suggests, do mathematical operations on the operands and return the result.
We have the following arithmetic operators:
- Addition (
+
): adds two numbers together. For examplea = 1 + 2
- Subtraction (
-
): subtracts two numbers. For examplea = 1 — 2
- Multiplication (
*
): multiplies two numbers together. For examplea = 1 * 2
- Division (
/
): divide two numbers. For examplea = 1 /2
- Remainder (
%
): gets the remainder of one number divided by another. For example:5 % 2 // 1
- Increment (
++
): increases a number by 1. For example:let x = 1; x++ // x is 2
- Decrement (
--
): decreases a number by 1. For example:let x = 1; x-- // x is 0
String operator
There is only one operator for manipulating strings. That’s the concatenation operator, which is also represented by the +
sign. When you concatenate two strings, you combine two strings into one. For example, 'a' + 'b'
would evaluate to 'ab'
.
Bitwise operators
Bitwise operators convert operands to bits. Then the operators are applied to each bit and converted back to their original form. Negative numbers are represented by 2’s complement. 2’s complement means the number is a complement of its number with respect to 2 raised to the Nth power, and a complement of a binary number is the number that, when summed together, you get all zeroes. So the 2’s complement of 010
would be 110
since 010 + 110
is 1000
. The leftmost digit is 0, and the three digits to the right of it are all 0’s.
Below are bitwise operators in JavaScript:
- Bitwise AND — Each bit of the left operand does the AND operation with the corresponding bits of the right operand. So if the bits in the same position are both 1, then it will be 1; otherwise, it’s 0. For example, if we have the expression
5 & 2
, then the JavaScript interpreter will convert the operands to binary, which is0101 & 0010
. Then, after applying the&
operation to each bit, we get0000
, which is 0. - Bitwise OR — Each bit of the left operand does the OR operation with the corresponding bits of the right operand. For example, if we have the expression
5 | 2
, then the JavaScript interpreter will convert the operands to binary, which is0101 | 0010
. Then after applying the&
operation to each bit, we get0111
, which is 7. - Bitwise XOR — Each bit of the left operand does the XOR operation with the corresponding bits of the right operands. For example, if we have the expression
5 ^ 2
, then the JavaScript interpreter will convert the operands to binary, which is0101 ^ 0010
. Then after applying the&
operation to each bit, we get0111
, which is 7. - Bitwise NOT — the NOT operation is done to the bits of the operand. For example, if we have the expression
~5
, then the JavaScript interpreter will convert the operands to binary, which is~0101
. Then after applying the~
operation to each bit, we get1010
, which is -6. - Left shift operator, which shifts the bits of the left operand by the number of bits given by the right operand to the left, and shift in zeroes from the right. For example,
2 << 1
would be4
since the binary representation of 2 is10
. If we move it one place to the left and shift in a zero to the one’s digit, then we get100
, which is 4. - Right shift operator, which shifts the bits of the left operand by the number of bits given by the right operand to the right, and removing shifted bits. For example,
2 >> 1
would be 1 since the binary representation of 2 is10
. If we move it one place to the left and shift in a zero to the one’s digit, then we get1
, which is 1. - Zero fill right shift operator, which shifts the bits of the left operand by the number of bits given by the right operand to the right, removing shifted bits, and the left bits with zeroes. For example,
2 >>> 1
would be 1 since the binary representation of 2 is10
. If we move it one place to the left and shift in a zero to the one’s digit, then we get01
, which is 1.
Logical operators
Logical operators are useful for creating boolean variables. There are three logical operators in JavaScript.
We have the &&
operator, which returns the right operand when the left one is truthy. Otherwise, it returns a falsy value. For example '' && 1
would be ``
since empty string is falsy.
The ||
operator would return the left operand when the left one is truthy. Otherwise, it returns the right one. For example, 7 || 1
would be 7 since 7 is truthy, so it returns the first truthy value which is 7. On the other hand, '' || 1
would return 1 since empty string is falsy, and so it would return the second operand which is 1. This is also handy for setting the default value of a variable.
The NOT operator, denoted by !
returns false
if the operand is truthy and vice versa. For example !1
would return false
, and !0
would return true
.
Other operators
JavaScript has many other operators. Some handy ones include the conditional operator, comma operator, delete
operator, instanceof
operator, new
operator, typeof
operator, this
, await
, destructuring, and spread operator.
The conditional operator allows us to write conditional statements in one line. It’s denoted by a question mark with a colon separating the return value for when the condition is true and when it’s false. For example, if we have the following expression:
let biggerThan5 = x > 5 ? 'bigger than 5' : 'less than 5'
If x
is 6, then biggerThan5
would be true
. If x
is 1, then biggerThan5
is false
.
The comma operator lets us declare more than one variable in one line. For example, if we write:
let a = 1, b = 2;
Then a
is set to 1, and b
is set to 2. The two-variable setting expressions are always evaluated separately, no matter if you have parentheses or not.
The delete
operator lets us remove a property from an object or an entry of an array. For example, suppose we have:
let a = {foo: 'bar'};
delete a.foo
Then a
becomes an empty object since the property foo
was removed by the delete
statement.
For arrays, we can write:
let arr = [1,2,3];
delete a[1];
Then a[1]
becomes undefined
.
With the in
operator, we can check if a specified value exists in a given array. It’s mostly handy for numbers, booleans, and strings.
For example, suppose we have:
let arr = [1,2,3];
Then 3 in arr
would be true
. It doesn’t work well with objects since it doesn’t compare the contents inside an object, just checks if the reference is the same.
The instanceof
operator lets us check if the type of an object is the type given. For example, suppose we have:
let a = 'abc';
Then a instanceof String
would be true
since a
is a string.
The new
operator lets us create a new instance of an object. So we can do:
let date = new Date()
if we want to create a new Date
object, which is a built-in object in all browsers that support JavaScript.
The this
is a special operator for getting the properties of an instance, which depends on where this
is located.
The typeof
operator returns a string which is the name of the type of the object. For example, if we have:
let a = 'abc';
Then typeof a
would be `string’
.
The await
operator lets us chain promises without using the then
function and passing a callback to it. It returns a promise after resolving the promise in the operand of the await
operator.
One very useful operator is the spread operator, which allows us to set entries of an array into individual variables and also add or update properties from one object to another. This operator also works with function calls. It’s denoted by ...
. For example, we can write the following to get the numbers from the num1
array into num2
:
let num1 = [1,2]
let num2 = [3,4,5, ...num1] // [3,4,5,1,2]
To use it in a function, we can write:
const sum = (a,b) => a + b;
sum(...num1) // returns 3
If you have more entries in your array than the number of parameters in your function, then it’ll ignore the array indexes that are beyond the number of parameters in the function. For example, if you spread num2
instead of num1
in sum
, you get 7 since a
would be 3 and b
would be 4. If you have less, then the arguments that are beyond the array length would be undefined
. For example, if you spread [1]
into the arguments of sum
, you get NaN
since 1 + undefined
is NaN
.
Another very useful operator is the destructuring operator, which lets you decompose objects and arrays into individual variables. For example, if we write:
let [one, two] = [1,2]
then one
would be 1 and two
would be 2. For objects, if we write:
let {foo, bar} = {foo: 1, bar: 2}
then variable foo
has value 1 and bar
has value 2.
Combining Operators
We can combine assignment operators with all mathematical operators, which include arithmetic operators and bitwise operators. For example, if we have x
set to 1 and y
set to 2, and we want to set x
to the sum of x
and y
, we write x += y
, which is the same as x += y
.
JavaScript has many operators. They allow us to do a lot of things. Almost all non-trivial programs will need to combine all these operators in many ways and places, in addition to statements like loops and conditionals.