When used on objects, operators typically call the valueOf()
and/or toString()
method to retrieve a value they can work with.
Operators that work on only one value are called unary operators. They are the simplest operators in ECMAScript.
Prefix increment / decrement: the variable’s value is changed before the statement is evaluated.
Postfix increment / decrement: the increment or decrement doesn’t occur until after the containing statement has been evaluated.
let num1 = 2;
let num2 = 20;
let num3 = num1-- + num2;
let num4 = num1 + num2;
console.log(num3); // 22
console.log(num4); // 21
Number()
first. If it used on NaN
, it will return NaN
.+
: When the unary plus is applied to a nonnumeric value, it performs the same conversion as the Number()
casting function.
-
: The unary minus operator’s primary use is to negate a numeric value, such as converting 1 into –1.
All numbers in ECMAScript are stored in IEEE–754 64-bit format, but the bitwise operations do not work directly on the 64-bit representation. Instead, the value is converted into a 32-bit integer, the operation takes place, and the result is converted back into 64 bits. To the developer, it appears that only the 32-bit integer exists because the 64-bit storage format is transparent.
A curious side effect of this conversion is that the special values NaN
and Infinity
both are treated as equivalent to 0
when used in bitwise operations.
Negative numbers are also stored in binary code but in a format called two’s complement. (负数以二进制补码形式表示)
If a bitwise operator is applied to a nonnumeric value, the value is first converted into a number using the Number()
function (this is done automatically) and then the bitwise operation is applied. The resulting value is a number.
let num1 = 25; // binary 00000000000000000000000000011001
let num2 = ~num1; // binary 11111111111111111111111111100110
let num3 = -num1 - 1;
console.log(num2); // -26
console.log(nume); // -26
The bitwise NOT is represented by a tilde (~
) and simply returns the one’s complement (反码) of the number. It negates the number and subtracts 1.
Realistically, though this returns the same result, the bitwise operation is much faster because it works at the very lowest level of numeric representation.
let a = 25; // 0000 0000 0000 0000 0000 0000 0001 1001
let b = 3; // 0000 0000 0000 0000 0000 0000 0000 0011
let result1 = 25 & 3; // 0000 0000 0000 0000 0000 0000 0000 0001
let result2 = 25 | 3; // 0000 0000 0000 0000 0000 0000 0001 1011
let result3 = 25 ^ 3; // 0000 0000 0000 0000 0000 0000 0001 1010
console.log(result1); // 1
console.log(result2); // 27
console.log(result3); // 26
let oldValue = -2; // 1111 1111 1111 1111 1111 1111 1111 1110 补码
let newValue = oldValue << 5; // 1111 1111 1111 1111 1111 1111 1100 0000 补码左移末尾补0, 不论正负
console.log(newValue); // 1000 0000 0000 0000 0000 0000 0100 0000 原码 -64
注意负数是对其补码进行移位.
一个有效的左移最高位和数据最高位必然一致, 再加上其末尾永远补0, 故算术左移和逻辑左移一样。#
So, the left shift preserves the sign of the number it’s operating on.
let oldValue1 = -64; // 1111 1111 1111 1111 1111 1111 1100 0000 补码, 有符号整数
let newValue1 = oldValue >> 5; // 1111 1111 1111 1111 1111 1111 1111 1110 -2
let oldValue2 = -64; // 1000 0000 0000 0000 0000 0000 0100 0000 补码, 无符号整数
let newValue2 = oldValue >>> 5; // 0000 0100 0000 0000 0000 0000 0000 0010, 补码, 13421772
The logical NOT operator first converts the operand to a Boolean value using Boolean()
and then negates it.
By using two NOT operators in a row, you can effectively simulate the behavior of the Boolean()
casting function.
console.log(!!"blue"); // true
console.log(!!NaN); // false;
let found = "";
let result = found && someUndeclaredVariable;
console.log(result); // ""
let found = "";
let result = found || someUndeclaredVariable;
console.log(result); // undefined
Opposed to logical AND, if the boolean equivalent of the first operand is true, return it. Else, return the second operand.
You can also use this behavior to avoid assigning a null or undefined value to a variable.
let myObject = preferredObject || backupObject;
There are three multiplicative operators in ECMAScript: multiply(*), divide(/), and modulus(%).
If either of the operands for a multiplication operation isn’t a number, it is converted to a number behind the scenes using the Number()
casting function.
Infinity
or –Infinity
is returned.NaN
, the result is NaN
.Infinity
is multiplied by 0
, the result is NaN
.Infinity
is multiplied by any finite number other than 0, the result is either Infinity
or –Infinity
, depending on the sign of the second operand.Infinity
is multiplied by Infinity
, the result is Infinity
.Number()
and then the other rules are applied.Multiplier1\Multiplier2 | other number | 0 |
Infinity / -Infinity |
NaN |
---|---|---|---|---|
other number | other number / Infinity / -Infinity |
0 |
Infinity / -Infinity |
NaN |
0 |
0 |
0 |
NaN |
NaN |
Infinity / -Infinity |
Infinity / -Infinity |
NaN |
Infinity / -Infinity |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
1 / 0 === Infinity
The divide operator, like the multiply operator, has special behaviors for special values. They are as follows:
Infinity
or –Infinity
, e.g. 1 / 0 === Infinity
NaN
, the result is NaN
.Infinity
is divided by Infinity
, the result is NaN
.zero
is divided by zero
, the result is NaN
.Infinity
or –Infinity
, depending on the sign of the first operand.Infinity
is divided by any number, the result is either Infinity
or –Infinity
, depending on the sign of the second operand.Number()
and then the other rules are applied.Dividend\Divisor | other number | 0 |
Infinity / -Infinity |
NaN |
---|---|---|---|---|
other number | other number / Infinity / -Infinity |
Infinity / -Infinity |
0 |
NaN |
0 |
0 |
NaN |
0 |
NaN |
Infinity / -Infinity |
Infinity / -Infinity |
Infinity / -Infinity |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN
, the result is NaN
.NaN
.0
, the result is NaN
.Number()
and then the other rules are applied.Dividend\Divisor | other number | 0 |
Infinity / -Infinity |
NaN |
---|---|---|---|---|
other number | other number | NaN |
other number | NaN |
0 |
0 |
NaN |
0 |
NaN |
Infinity / -Infinity |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
NaN |
console.log(Math.pow(3, 2); // 9
console.log(3 ** 2); // 9
console.log(Math.pow(16, 0.5); // 4
console.log(16** 0.5); // 4
let squared = 3;
squared **= 2;
console.log(squared); // 9
As with the multiplicative operators, conversions occur behind the scenes for different data types.
The addition operator either performs string concatenation or numeric addition.
NaN
, the result is NaN
.Infinity
is added to Infinity
, the result is Infinity
.–Infinity
is added to –Infinity
, the result is –Infinity
.Infinity
is added to –Infinity
, the result is NaN
.+0
is added to +0
, the result is +0
.–0
is added to +0
, the result is +0
.–0
is added to –0
, the result is –0
.Number()
, and throw error:valueOf()
first. If it return an object, call toString()
method subsequently. and Apply the rules below.toString()
method will perform precede valueOf()
.NaN
, the result is NaN
.Infinity
is subtracted from Infinity
, the result is NaN
.–Infinity
is subtracted from –Infinity
, the result is NaN
.-Infinity
is subtracted from Infinity
, the result is Infinity
.Infinity
is subtracted from –Infinity
, the result is -Infinity
.+0
is subtracted from +0
, the result is +0
.–0
is subtracted from +0
, the result is -0
.-0
is subtracted from –0
, the result is +0
.null
, or undefined
, it is converted to a number (using Number()
behind the scenes) and the arithmetic is calculated using the previous rules.valueOf()
method is called to retrieve a numeric value to represent it. If the object doesn’t have valueOf()
defined or return an object, then toString()
is called and the resulting string is converted into a number.Relational operators include less-than (<), greater-than (>), less-than-or-equal-to (<=), and greater-than-or-equal-to (>=).
There are some conversions and other oddities that happen when using different data types.
NaN
is false
.valueOf()
and use its result to perform the comparison according to the previous rules. If valueOf()
is not available or returns an object, call toString()
and use that value according to the previous rules.==
) and not equal (!=
) to perform conversion before comparison, and identically equal (===
) and not identically equal (!==
) to perform comparison without conversion.Both operators do conversions to determine if two operands are equal (often called type coercion).
When performing conversions, the equal and not-equal operators follow these basic rules:
null
and undefined
are equal. And they cannot be converted into any other values for equality checking. (null == 0
returns false
)null
and undefined
will converted to number type for comparison.
NaN
, the equal operator returns false
and the not-equal
operator returns true. Important note: even if both operands are NaN
, the equal operator returns false
because, by rule, NaN
is not equal to NaN
.valueOf()
and toString
methods are called on the object in order to retrieve a primitive value to compare according to the previous rules.let result1 = (null < 0); // false, null is converted to 0;
let result2 = (null == 0); // false, null will not converted to 0.
let result3 = (null <= 0); // true, null is converted to 0;
let result1 = ("55" == 55); // true
let result2 = ("55" === 55); // false
let result3 = (null == undefined); // true
let result4 = (null === undefined); // false
variable = boolean_expression ? true_value : false_value;
let num = 10
let num1 = 1, num2 = 2, num3 = 3;
it can also be used to assign values. When used in this way, the comma operator always returns the last item in the expression
let num = (5, 1, 4, 8, 0); //num becomes 0
Reference: