Categories
JavaScript

Comprehensive Guide to JavaScript Operators and Expressions

Spread the love

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 and yield* 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 be true, and 3 == '3' would also be true.
  • Inequality operator (!=), which also compares only the content of objects without the type. For example, 1 != 1 would be false , and 1 != '1' would also be false.
  • Strict equality operator (===), which compares both the content and the type of objects for equality. For example, 1 === “1” would be false, and 1 === 1 would be true.
  • Strict inequality (!==), which compares both the content and the type of object for inequality. For example, 3 !== “3” would be true, and 3 !== 3 would be false .
  • Greater than operator (> ), which compares the value of two numbers and evaluates to true if the number left of the greater than sign is bigger than the right one. For example, 7 > 2 would be true.
  • Greater than or equal to operator (>= ), which compares the value of two numbers and evaluates to true if the number left of the greater than sign is bigger than or equal to the right one. For example, 1 >= 1 would be true.
  • Less than operator (< ), compares the value of two numbers and evaluates to true if the number left of the greater than sign is smaller than the right one. For example, 1< 2 would be true.
  • Less than or equal to operator (<= ), which compares the value of two numbers and evaluates to true if the number left of the greater than sign is smaller than or equal to the right one. For example, 1 <= 1 would be true.

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 example a = 1 + 2
  • Subtraction (-): subtracts two numbers. For example a = 1 — 2
  • Multiplication (*): multiplies two numbers together. For example a = 1 * 2
  • Division (/): divide two numbers. For example a = 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 is 0101 & 0010. Then, after applying the & operation to each bit, we get 0000 , 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 is 0101 | 0010 . Then after applying the & operation to each bit, we get 0111 , 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 is 0101 ^ 0010 . Then after applying the & operation to each bit, we get 0111 , 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 get 1010, 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 be 4 since the binary representation of 2 is 10. If we move it one place to the left and shift in a zero to the one’s digit, then we get 100 , 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 is 10 . If we move it one place to the left and shift in a zero to the one’s digit, then we get 1 , 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 is 10. If we move it one place to the left and shift in a zero to the one’s digit, then we get 01 , 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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *