JavaScript Operators are as rich as what you‘d expect from any modern language. There are four categories: arithmetic, comparison, assignment, and logical.
Arithmetic operators perform basic computations on their operands (the variables they operate on).
In the table below, variable a
has a value of 2 before the operation is applied.
Operator | Operation | Expression | Result |
---|---|---|---|
+ | Add | 2 + a | 4 |
- | Substract | 2 - a | 0 |
* | Multiply | 3 * a | 6 |
/ | Divide | 3 / a | 1.5 |
% | Modulus - division remainder | 7 % a | 1 |
++ | Increment - increase by 1 | a++ | 3 |
-- | Decrement - decrease by 1 | a-- | 1 |
The + operator is used for adding numeric values, but it can also be used to concatenate (join) two or more strings and return a single string. Here is an example:
var str1 = "Hello";
var str2 = " Vivek";
str1 = str1 + str2; // => "Hello Vivek"
console.log(str1);
The last statement can also be rewritten by using the assignment += operator as follows:
var str1 = "Hello";
var str2 = " Vivek";
str1 += str2; // => "Hello Vivek"
console.log(str1);
Comparison operators compare the value of two operands. If the comparison is true, they return
true, otherwise false. In the table below the variables are: a = 1
and b = 2
.
Operator | Operation | Expression | Result |
---|---|---|---|
== | Equal to | a == b | false |
!= | Not equal to | a != b | true |
<= | Less than equal to | a <= b | true |
>= | Greater than or equal to | a >= b | false |
< | Less than | a < b | true |
> | Greater than | a > b | false |
In an assignment operation the value of a variable is computed from the expression that lies
to the right of an assignment operator. That value is assigned to the variable or property that
is on the left side of the operator. In the table below the variables have the following values:
a = 1
, b = 2
, and c = 3
.
Operator | Operation | Result |
---|---|---|
= | a = b + c; | a = 5 |
+= | a += b; // equivalent to a = a + b | a = 3 |
-= | a -= b; // equivalent to a = a – b | a = -1 |
/= | a /= b; // equivalent to a = a / b | a = 0.5 |
%= | c %= b; // equivalent to c = c % b | c = 1 |
*= | a *= b; // equivalent to a = a * b | a = 2 |
Logical or boolean operators compare boolean expressions and then return true or false.
The &&
and ||
('and' and 'or') operators take two operands.
The !
('not') operator takes a single operand. In the table below the
variables have the following values: a = 1
and b = 2
.
Operator | Operation | Expression | Result |
---|---|---|---|
&& | Logical and. Returns true only if both its first and second operands are evaluated to true. | a < 3 && b > 5 | returns false as b > 5 is false |
|| | Logical or. Returns true if one of the two operands are evaluated to true, returns false if both are evaluated to true. | a < 3 || b > 5 | returns true as a < 3 is true |
! | Logical not. Unary operator that simply inverts the boolean value of its operand. | !(b>5) | returns true |
In most languages, dividing a number by 0 throws an error and stops program execution. JavaScript however, returns a special infinity value, printed as Infinity, when the result of a numeric operation is larger than the largest representable number.
Similarly, it returns a negative infinity value, printed as -Infinity, when the resulting negative value becomes more negative than the most negative representable number.
In both cases, the program simply continues with its execution!
10 / 0; // => Infinity -10 / 0; // => -Infinity 2 / +0; // => +Infinity 2 / -0; // => -Infinity
Notice the -0 in the last statement. Negative 0 means it is a negative value closer to 0, but
the value is so small that it cannot be represented with available precision. For instance,
when you take -Number.MIN_VALUE
(the smallest possible negative number,
i.e. -5e-324) divided by 5, you get -0. Similarly, -1 divided by Infinity returns -0. Note that
according to IEEE 754 specification, -0 is equal to 0.
In JavaScript when an arithmetic operation fails it does not throw an error; instead it returns a special numeric value, called NaN (for Not a Number), and the program happily continues with execution. The following operations all result in NaN:
Infinity / Infinity; // => Nan. 0 / 0; // => Nan. "Hello" / 1; // => Nan. "Hello" cannot be converted to number Math.sqrt(-1); // => Nan. NaN / 0; // => Nan. Any operation with NaN results in NaN
The JavaScript typeof operator does not distinguish between NaN and numbers, therefore the
expression typeof NaN === "number"
returns true. Furthermore, NaN does
not compare equal to any number, including a comparison with itself, thus NaN == NaN
returns false.
You need to be aware how NaN can affect computations which involves multiple steps. If you have a sequence of arithmetic operations and you get NaN as the final result, it means that either one of the initial inputs was NaN or NaN is produced somewhere in the chain.
The built-in function isNaN
is used to determine whether a given value is NaN.
It will return true if it is, and false if not. When a value is confirmed to be NaN, it is up to you
how you deal with the value. You could do something like this (set it to zero):
var profit = NaN; if (isNaN(profit)) { profit = 0; }
Rather than using isNaN
, a better approach would be to use the built-in
function isFinite
to determine whether a value can be used as a number or not.
This function checks for both Infinity and NaN. Before calling isFinite
make
sure that the value passed is actually a number, like so:
var isNumber = function (val) {
if (typeof val === "number") {
return isFinite(val);
}
return false;
}
var n = 3.6;
console.log(isNumber(n)); // => true
n = NaN;
console.log(isNumber(n)); // => false
n = Infinity;
console.log(isNumber(n)); // => false
In terms of numeric precision, JavaScript may not give you the exact values you would expect.
0.119 / 100; // => evaluates to 0.0011899999999999999 0.14 / 100; // => evaluates to 0.0014000000000000002
The reason for these rounding imprecisions is that JavaScript uses a binary floating-point format for number. Binary floating-point representations can exactly represent fractions like 1/16, and 1/32, 1/64, 1/128, but not fractions like 1/100, 1/10 which are very common in monetary calculations. This can cause some rounding limitations like the examples below:
var diff1 = .5 - .4; // => 0.09999999999999998
var diff2 = .4 - .3; // => 0.10000000000000003
console.log(diff1 == diff2); // => false, the values are not the same
The last statement can be rather disheartening. Both diff1
and
diff2
are very close to .1, but not exact. So, be aware of JavaScript's
internal number representations.
In the C language, copying a string is frequently coded as the following one-liner:
while (*str1++ = *str2++);
This code tends to be tricky and confuse developers that are not too familiar with the 'pre' and 'post' nature of increment and decrement operators. Although JavaScript does not support pointers, the terseness of the ++ and -- operators is something that will need to be looked at carefully. For example, even an experienced JavaScript programmer will need some time to figure out what the following statement does:
var m = 7;
m = m++ + --m;
console.log(m) // what is the value of m?
Clearly, this makes the code unnecessarily complex and hard to understand. It is best to use the ++ and -- operators on a single line which enhances program readability. For example:
count++; elements[count] = 10;
Anything beyond that can be confusing; chances of making typos are high.
However, JavaScript loops can safely use the increment operators within a for-loop because it is standard practice and usually does not cause confusion.
for(var i = 0, j = cost.length; i < 5; i++, j++) { cost[j] = val[i]; }
If you minify JavaScript code, be very careful when using ++ and -- operators. Minimizers remove
unnecessary whitespace and comments from your JavaScript code. As an example, it may translate
i + ++j
into i+++j
. The compiler then treats the resulting
expression as i++ + j
which is incorrect. Fortunately, this is easily
corrected by adding parentheses like
so: i + (++j)
. So the lesson here
is to always add parenthesis to make your intentions clear.
It is also good practice to run JSLint before minifying your code, as it checks for these and other potential problems related to the ++ and -- operators.
The ==
operator compares the values of its operands. If their values are equal, it returns true.
If the operands have different data types, JavaScript attempts to convert these to an appropriate
type then compares their values. Consider this:
console.log("1" == 1); // => true
Here the string "1" is compared to the numeric 1. JavaScript converts the string numeric literal to a number value. Since they are equal, it returns true. How about this:
console.log(false == "0"); // => true
This returns true. In this case, both operands are converted to numbers. Boolean true values are converted to 1 and false to 0. And the string "0" is converted to the number 0. Following the conversions JavaScript compares 0 == 0 and returns true.
Here are a few more cases:
console.log(null == undefined); // => true
console.log(true == "1"); // => true
console.log("9" < "P"); // => true
In the last expression, the ASCII values for numbers are lower than those for letters, returning true.
The rules of data conversion with the ==
operator are complex and hard to remember.
This can easily lead to bugs. Fortunately JavaScript offers an alternative, called the strict
equality operator (===
) which does not convert data when testing for equality.
It only returns true when 1) the operands being compared are of the same type, and
2) their values are the same. Here are some examples:
console.log("1" === 1); // => false
console.log(true === !false); // => true
If both operands are objects and if they refer to the same object, then JavaScript returns true. Let's see how this works with, say, arrays:
var ref1 = [10, 20]; // an array
var ref2 = [10, 20]; // a second array
console.log(ref1 == ref2); // => false
console.log(ref1 === ref2); // => false
Here ref1 == ref2
returns false, because they reference different arrays.
The strict comparison ref1 === ref2
also return false because,
although they have the same values, these are two different arrays in memory.
As in many other languages, JavaScript strings are immutable meaning that the contents of a string object
cannot be changed after the object is created, although the syntax makes it appear as if you can do this.
Let's see how this affects ==
and ===
operations:
var str1 = "Hello World"; // a string
var str2 = "Hello" + " World"; // another string
console.log(str1 == str2); // => true
console.log(str1 === str2) // => true
Here str1
and str2
reference the same immutable "Hello World"
string and therefore both ==
and ===
return true.
How about comparing string objects created with the String constructor and with a string literal?
console.log("Hello" == new String("Hello")); // => true
console.log("Hello" === new String("Hello")); // => false
The ==
operator converts these objects on either side to the same type and then returns true because
their values are the same. The ===
operator understands that the objects are not of the same type and
therefore immediately returns false without even looking at their values.
The table below summarizes the bitwise operators in JavaScript:
Operator | Usage | Result |
---|---|---|
Bitwise AND | a & b | Returns 1 for each bit position where both operands are 1 |
Bitwise OR | a | b | Returns 1 for each bit position where either operand is 1 |
Bitwise XOR | a ^ b | Returns 1 for each bit position where either but not both are 1 |
Left shift | a << b | Shifts in binary fashion all bits one position to the left; discarding the left bit and filling the right bit with 0. |
Right shift | a >> b | Shifts in binary fashion all bits one position to the right, discarding the right bit. This operations maintains the original sign (+ or -). |
0-fill right shift | a >>> b | Shifts in binary fashion all bits one position to the right, discarding the right bit and filling the left bit with 0. |
JavaScript does not support an integer type. All numbers in JavaScript are stored in 64-bit floating point format i.e. double precision floating point. The bitwise operators that manipulate numbers at the bit level do not perform operations directly on this 64-bit floating-point representation. Instead, they coerce the numeric values to signed 32-bit integers, do the necessary operation, and again convert the result back to floating point format. This conversion has a performance impact.
You get the correct results for only up to 32 bits. During the conversion to 32-bit, the fractional part and any bits beyond the 32nd are dropped. If you have more bits than that, the value gets rounded to the nearest representable floating-point number.
var a = 0xFFFFFFFFF; // => 36 bits all set to 1
var b = 0xFFFFFFFFF; // => 36 bits all set to 1
var c = a & b; // bitwise AND
console.log(c); // => -1
You may expect that c's value has all 36 bits set to 1 following the bitwise & operation, but because of the conversion to 32-bits that is not the case. JavaScript converts to 32-bit, executes the bitwise AND operation, and the resulting 32-bits are all set to 1 which is equal to -1.
Let's look at an example with floating point numbers:
var a = 2.6; // represented as bits 0010, fractional part discarded
var b = 6.2 // represented as bits 0110, fractional part discarded
var c = a & b; // => bits 0010, which is equal to 2
console.log(c); // => 2
Strangely, if you use NaN,
Infinity
, or -Infinity
as
operands in bitwise operations, they are converted to 0.
In all C-like languages, bitwise operators are extremely fast. Until recently, they were slow in JavaScript but the latest versions of web browsers can JIT-compile JavaScript code. These operations have accelerated enough to be useful.
Bitwise manipulations are typically close to the hardware and therefore they don't come up very often in JavaScript programming.
A common mistake it to use bitwise & and | operators instead of logical && and || operators. This can lead to hard-to-detect bugs. Here is what may happen. Say we have a variable x with a value of 5 and you have mistakenly typed & instead of &&.
var x = 5;
if (x > 5 & x < 8) {
console.log(true);
} else {
console.log(false);
}
This is false, which is the same if you had typed the && operator: if (x<=5 && x>7)
.
Although we are getting the expected result, we have improperly used a logical & operator which is
intended for bit-level operations only. Again, be aware of this mistake as it can lead to difficult
to find bugs.