JavaScript 常见运算符
维基百科 --- 运算符
编程语言通常支持一组运算符:构造,其行为通常类似于函数,但在语法 或语义上 与通常的函数不同。常见的简单示例包括算术(加法
+
),比较(加>
)和逻辑运算(如AND
或&&
)。更多涉及的示例包括赋值 (通常=
或:=
),记录或对象(通常)中的字段 访问.
,以及范围解析运算符 (通常::
)。语言通常定义一组内置运算符,在某些情况下允许用户定义的运算符。
运算符的优先级
简单记忆法(需要具体问题具体分析):单目 > 算术 > 位移 > 关系 > 逻辑 > 三目 > 赋值
下面的表将所有运算符按照优先级的不同从高到低排列。
MDN
运算符优先级
优先级 | 运算类型 | 关联性 | 运算符 |
---|---|---|---|
20 | 圆括号 | n/a | (expr) |
19 | 成员访问 | 从左到右 | object.property |
需计算的成员访问 | 从左到右 | object[property] | |
new (带参数列表) | n/a | new Object(params) | |
函数调用 | 从左到右 | Function(params) | |
可选链(Optional chaining) | 从左到右 | a?.b | |
18 | new (无参数列表) | 从右到左 | new Object() |
17 | 后置递增(运算符在后) | n/a | expr++ |
后置递减(运算符在后) | n/a | expr-— | |
16 | 逻辑非 | 从右到左 | !expr |
按位非 | ~expr | ||
一元加法 | +expr | ||
一元减法 | -expr | ||
前置递增 | ++expr | ||
前置递减 | —expr | ||
typeof | typeof expr | ||
void | void expr | ||
delete | delete expr | ||
await | await expr | ||
15 | 幂 | expr**expr | |
14 | 乘法 | 从左到右 | expr * expr |
除法 | expr / expr | ||
取模 | expr % expr | ||
13 | 加法 | 从左到右 | expr + expr |
减法 | expr - expr | ||
12 | 按位左移 | 从左到右 | expr << expr |
按位右移 | expr >> expr | ||
无符号右移 | expr >>> expr | ||
11 | 小于 | 从左到右 | expr < expr |
小于等于 | expr <= expr | ||
大于 | expr > expr | ||
大于等于 | expr >= expr | ||
in | expr in expr | ||
instanceof | expr instanceof expr | ||
10 | 等号 | 从左到右 | expr = expr |
非等号 | expr != expr | ||
全等号 | expr === expr | ||
全等号 | expr !== expr | ||
9 | 按位与 | 从左到右 | expr & expr |
8 | 按位异或 | 从左到右 | expr ^ expr |
7 | 按位或 | 从左到右 | expr \| expr |
6 | 逻辑与 | 从左到右 | expr && expr |
5 | 逻辑或 | 从左到右 | expr \|\| expr |
4 | 条件运算符 | 从右到左 | expr ? expr : expr |
3 | 赋值 | 从右到左 | expr = expr |
expr += expr | |||
expr -= expr | |||
expr *= expr | |||
expr /= expr | |||
expr %= expr | |||
expr <<= expr | |||
expr >>= expr | |||
expr >>>= expr | |||
expr &= expr | |||
expr \|= expr | |||
expr ^= expr | |||
2 | yield | 从右到左 | yield expr |
yield* | 从右到左 | yield* expr | |
1 | 展开运算符 | n/a | ...expr |
0 | 逗号 | 从左到右 | expr, expr |
1. 单目运算符
一元(单目)运算符只需要一个操作变量。
+
: 一元加运算符将操作转换为Number类型.
-
: 一元减运算符将操作转换为Number类型并取反.
!
: 逻辑非运算符.
~
: 按位非运算符.
delete
: 运算符用来删除对象的属性.
void
: 运算符表示表达式放弃返回值.
typeof
: 运算符用来判断给定对象的类型.
var obj = { a: 123 };
function test() {}
console.log('before delete:', obj);
typeof obj;
delete obj.a;
console.log('typeof', typeof obj);
console.log('typeof', typeof test);
console.log('typeof', typeof '123');
console.log('typeof', typeof 321);
console.log('typeof', typeof undefined);
console.log('typeof', typeof null);
console.log('after delete:', obj);
console.log('void 0:', void 0);
console.log("+'1':", +'1');
console.log('+ object:', +obj);
console.log('+ function:', +test());
console.log('+ undefied:', +undefined);
console.log('+ null:', +null);
console.log('-1:', -1);
console.log("-'1':", -'1');
console.log('- object:', -obj);
console.log('- function:', -test());
console.log('- undefied:', -undefined);
console.log('- null:', -null);
console.log('!1:', !1);
console.log('!0:', !0);
console.log("!'1':", !'1');
console.log('~1:', ~1);
console.log("~'1':", ~'1');
2. 自增 &
自减运算符
++a
: 先赋值后自增
a++
: 先赋值后自增
—-a
: 先自减后赋值
a-—
: 先自减后赋值
var a = 0;
console.log('a++', a++);
console.log('a', a);
console.log('++a', ++a);
var b = 0;
console.log('b--', b--);
console.log('b', b);
console.log('--b', --b);
3. 算术运算符
2个数值(字面量或变量)作为操作数,并返回单个数值.
主要有+
-
*
/
%
.
4. 位移运算符
在二进制的基础上对数字进行移动操作
<<
: 按位左移运算符. 左移 当前值的二进制 *
2 ^
(位数)
>>
: 按位右移运算符. 左移 当前值的二进制 /
2 ^
(位数)
>>>
: 按位无符号右移运算符.
有符号整数使用 31
位表示整数的数值,用第 32
位表示整数的符号,0 表示正数,
1表示负数。数值范围从
-2147483648到
2147483647`。
二进制表示规则
正数左右位移
console.log('8 << 3', 8 << 3);
console.log('-1 << 3', -1 << 3);
console.log('8 >> 3', 8 >> 3);
console.log('-1 >> 3', -1 >> 3);
console.log('8 >>> 3', 8 >>> 3);
console.log('-1 >>> 3', -1 >>> 3);
5. 位运算符(Bitwise operators)
将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值。
&
: 全1
为1
|
: 见1
为1
^
: 同为1
, 异为0
~
:1
变0
,0
变1
The production UnaryExpression :
**~**
UnaryExpression* is evaluated as follows:
- Let expr be the result of evaluating UnaryExpression.
- Let oldValue be ToInt32(GetValue(expr)).
- Return the result of applying bitwise complement to oldValue. The result is a signed 32-bit integer.
中文:
产生式
UnaryExpression : ~ UnaryExpression
按照下面的过程执行:
- 令
expr
为解析执行UnaryExpression
的结果- 令
oldValue
为 ToInt32(GetValue(expr
))- 返回
oldValue
按位取反的结果
ToInt32
过程:The abstract operation ToInt32 converts its argument to one of 232 integer values in the range −231 through 231−1, inclusive. This abstract operation functions as follows:
- Let number be the result of calling ToNumber on the input argument.
- If number is NaN, +0, −**0, +**∞, or −∞, return +0.
- Let posInt be sign(number) - floor(abs(number)).
- Let int32bit be posInt- modulo 232; that is, a finite integer value k of Number type with positive sign and less than 232 in magnitude such that the mathematical difference of posInt* and k is mathematically an integer multiple of 232.
- If int32bit is greater than or equal to 231, return int32bit − 232, otherwise return int32bit.
中文:
- 令
number
为调用 ToNumber 将输入参数转化为数值类型的结果- 如果
number
是 NaN,+0,-0,+∞ 或者 -∞,返回 +0- 令
posInt
为 sign(number
) * floor(abs(number
))- 将
posInt
进行取模处理,转化为在 −2^31 到 2^31−1 之间的 32 位有符号整数并返回- 如果
int32bit
大于或等于2^31
,则返回int32bit
-2^32
,否则返回int32bit
。从效果上看,ToInt32 依次做了这样几件事:
- 类型转换,非数值类型的需要转化为数值类型
- 特殊值处理,NaN 和 ∞ 都被转化为 0
- 取整,如果是浮点数,会损失小数点后面的精度
- 取模,将整数调整到 32 位有符号整数区间内,如果整数原本不在这个区间,会丧失精度
- 边界处理
~~
:将操作数转化为 32 位有符号整数
The production UnaryExpression :
**~**
UnaryExpression* is evaluated as follows:中文:
产生式
UnaryExpression : ~~ UnaryExpression
按照下面的过程执行:
- 令
expr
为解析执行UnaryExpression
的结果- 返回 ToInt32(GetValue(
expr
))
console.log('2 & 3:', 2 & 3);
console.log('2 | 3:', 2 | 3);
console.log('~3:', ~3);
console.log('~~3:', ~~3);
console.log('~~undefined:', ~~undefined);
console.log('~~null:', ~~null);
console.log('~~true:', ~~true);
console.log('~~false:', ~~false);
console.log('~~{}:', ~~{});
console.log('~~NaN:', ~~NaN);
console.log("~~'':", ~~'');
console.log("~~'test':", ~~'test');
console.log('---------------------');
console.log('~~ (Math.pow(2, 31) - 1):', ~~ (Math.pow(2, 31) - 1));
console.log('~~ (Math.pow(2, 31)):', ~~ (Math.pow(2, 31)));
console.log('~~ (-Math.pow(2, 31)):', ~~ (-Math.pow(2, 31)));
console.log('~~ (-Math.pow(2, 31) - 1):', ~~ (-Math.pow(2, 31) - 1));
console.log('~~ (Math.pow(2, 32)):', ~~ (Math.pow(2, 32)));
console.log('---------------------');
console.log('~~11.7:', ~~11.7);
console.log('~11.7:', ~11.7);
console.log('~~ -11.7:', ~~ -11.7);
console.log('~ -11.7:', ~ -11.7);
console.log('~~11.13:', ~~11.13);
console.log('~11.13:', ~11.13);
console.log('~~ -11.13:', ~~ -11.13);
console.log('~ -11.13:', ~ -11.13);
6. 关系运算符
比较运算符比较二个操作数并返回基于比较结果的Boolean
值
>
>=
<
<=
==
===
!=
!==
in
instanceof
==
,!=
与===
,!==
等于和全等,他们的区别是,前者会强制类型转换,再比较值。
var a;
console.log('1 == 1:', 1 == 1);
console.log('1 === 1:', 1 === 1);
console.log("1 == '1':", 1 == '1');
console.log("1 === '1':", 1 === '1');
console.log('1 == true:', 1 == true);
console.log('1 === true:', 1 === true);
console.log('0 == false:', 0 == false);
console.log('0 === false:', 0 === false);
console.log('a == undefined:', a == undefined);
console.log('a === undefined:', a === undefined);
console.log('0 == null:', 0 == null);
console.log('0 === null:', 0 === null);
7. 逻辑运算符
逻辑运算符典型的用法是用于boolean
(逻辑)值运算, 它们返回boolean
值。
&&
, ||
, !
, !!
(与,或,非, 双非),
如果一个值可以被转换为 true
,那么这个值就是所谓的 truthy,如果可以被转换为 false
,那么这个值就是所谓的 falsy。
truthy
: 在 JavaScript中,Truthy (真值)指的是在 布尔值 上下文中转换后的值为真的值。所有值都是真值,除非它们被定义为 falsy (即除了 false
,0
,""
,null
,undefined
和 NaN
外).
falsy
: falsy
(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.
会被转换为 false
的表达式有:
null
;NaN
;0
;空字符串(
""
or''
or ````);undefined
。!
: 逻辑非是将当前对象的Boolean
取反,即取当前是falsy
的值为true
,当前是true
的值为false
。The production UnaryExpression :
**!**
UnaryExpression* is evaluated as follows:- Let expr be the result of evaluating UnaryExpression.
- Let oldValue be ToBoolean(GetValue(expr)).
- If oldValue is true, return false.
- Return true.
中文:
产生式
UnaryExpression : ! UnaryExpression
按照下面的过程执行:- 令
expr
为解析执行UnaryExpression
的结果 - 令
oldValue
为 ToBoolean(GetValue(expr
)) - 如果
oldValue
为 true, 返回 false - 返回 true
!!
: 将操作数转化为布尔类型The production UnaryExpression :
**!!**
UnaryExpression* is evaluated as follows:中文:
产生式
UnaryExpression : !! UnaryExpression
按照下面的过程执行:- 令
expr
为解析执行UnaryExpression
的结果 - 返回 ToBoolean(GetValue(
expr
))
由于逻辑表达式的运算的顺序是从左到右,也可以用以下规则进行"短路"计算,
console.log(true && true);
console.log(true && false);
console.log(false && false);
console.log(true || true);
console.log(true || false);
console.log(false && true);
// 逻辑表达式从左往右运算
console.log(true && false || true);
console.log(true && true || false);
console.log(false && false || true);
console.log(true && true || false);
console.log(true && true || true);
console.log('!true', !true);
console.log('!false', !false);
console.log('!1', !1);
console.log('!0', !0);
console.log('!!true', !!true);
console.log('!!false', !!false);
console.log('!!null', !!null);
console.log('!!undefiend', !!undefined);
console.log('!!1', !!1);
console.log('!!0', !!0);
console.log("!!''", !!'');
console.log("!!'test'", !!'test');
console.log('!!{}', !!{});
8. 条件(三元)运算符
?:
: 是 JavaScript
仅有的使用三个操作数的运算符。本运算符经常作为if
语句的简短形式来使用。
console.log(true ? 'true' : 'false');
console.log(false ? 'true' : 'false');
// 多个条件判断
console.log(true ? 'true' : true ? 'false true' : 'false');
console.log(false ? 'true' : true ? 'false true' : 'false');
9. 赋值运算符
=
+=
-=
*=
/=
%=
**=
(平方) <<=
>>=
>>>=
&=
|=
^|
10. 可选链
var a = {};
console.log(a?.b);
var a = { b: 1 };
console.log(a?.b);
参考