Skip to main content

JavaScript 常见运算符

维基百科 --- 运算符

编程语言通常支持一组运算符:构造,其行为通常类似于函数,但在语法语义上 与通常的函数不同。常见的简单示例包括算术(加法+),比较(加>)和逻辑运算(如AND&&)。更多涉及的示例包括赋值 (通常=:=),记录或对象(通常)中的字段 访问.,以及范围解析运算符 (通常::)。语言通常定义一组内置运算符,在某些情况下允许用户定义的运算符。

运算符的优先级

简单记忆法(需要具体问题具体分析):单目 > 算术 > 位移 > 关系 > 逻辑 > 三目 > 赋值

下面的表将所有运算符按照优先级的不同从高到低排列。MDN运算符优先级

优先级运算类型关联性运算符
20圆括号n/a(expr)
19成员访问从左到右object.property
需计算的成员访问从左到右object[property]
new (带参数列表)n/anew Object(params)
函数调用从左到右Function(params)
可选链(Optional chaining)从左到右a?.b
18new (无参数列表)从右到左new Object()
17后置递增(运算符在后)n/aexpr++
后置递减(运算符在后)n/aexpr-—
16逻辑非从右到左!expr
按位非~expr
一元加法+expr
一元减法-expr
前置递增++expr
前置递减—expr
typeoftypeof expr
voidvoid expr
deletedelete expr
awaitawait expr
15expr**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
inexpr in expr
instanceofexpr 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
2yield从右到左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');

unary-operators

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);

arithmetic-operators1

3. 算术运算符

2个数值(字面量或变量)作为操作数,并返回单个数值.

主要有+ - * / %.

4. 位移运算符

在二进制的基础上对数字进行移动操作

<<: 按位左移运算符. 左移 当前值的二进制 * 2 ^ (位数)

>>: 按位右移运算符. 左移 当前值的二进制 / 2 ^ (位数)

>>>: 按位无符号右移运算符.

有符号整数使用 31 位表示整数的数值,用第 32 位表示整数的符号,0 表示正数,1表示负数。数值范围从-21474836482147483647`。

二进制转换规则图绘制地址

二进制表示规则

bitwise-show

正数左右位移

bitwise-operators-positive-number

bitwise-positive-negative-convert

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);

Displacement operator

5. 位运算符(Bitwise operators)

​ 将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值

  • &: 全11

  • |: 见11

  • ^: 同为1, 异为0

  • ~ : 1001

The production UnaryExpression : **~** UnaryExpression* is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.
  2. Let oldValue be ToInt32(GetValue(expr)).
  3. 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:

  1. Let number be the result of calling ToNumber on the input argument.
  2. If number is NaN, +0, −**0, +**∞, or −∞, return +0.
  3. Let posInt be sign(number) - floor(abs(number)).
  4. 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.
  5. 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:

  1. Let expr be the result of evaluating UnaryExpression.
  2. Return ToInt32(GetValue(expr)).

中文:

产生式 UnaryExpression : ~~ UnaryExpression 按照下面的过程执行:

  • expr 为解析执行 UnaryExpression 的结果
  • 返回 ToInt32(GetValue(expr))
console.log('2 & 3:', 2 & 3);
console.log('2 | 3:', 2 | 3);
console.log('~3:', ~3);

bitwise-operators

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);

bitwise-operators-2

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 (即除了 false0""nullundefinedNaN 外).

falsy: falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.

会被转换为 false 的表达式有:

  • null

  • NaN

  • 0

  • 空字符串("" or '' or ````);

  • undefined

    !: 逻辑非是将当前对象的Boolean取反,即取当前是falsy的值为true,当前是true的值为false

    The production UnaryExpression : **!** UnaryExpression* is evaluated as follows:

    1. Let expr be the result of evaluating UnaryExpression.
    2. Let oldValue be ToBoolean(GetValue(expr)).
    3. If oldValue is true, return false.
    4. Return true.

    中文:

    产生式 UnaryExpression : ! UnaryExpression 按照下面的过程执行:

    • expr 为解析执行 UnaryExpression 的结果
    • oldValue 为 ToBoolean(GetValue(expr))
    • 如果 oldValue 为 true, 返回 false
    • 返回 true

    !!: 将操作数转化为布尔类型

    The production UnaryExpression : **!!** UnaryExpression* is evaluated as follows:

    1. Let expr be the result of evaluating UnaryExpression.
    2. Return be ToBoolean(GetValue(expr*)).

    中文:

    产生式 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);

logical-operators

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');

conditional-operator

9. 赋值运算符

= += -= *= /= %= **=(平方) <<= >>= >>>= &= |= ^|

10. 可选链

var a = {};
console.log(a?.b);

var a = { b: 1 };
console.log(a?.b);

optional-chaining.png

参考

MDN表达式和运算符

ECMAScript

按位操作符Bitwise operators)

Annotated ECMAScript 5.1

js 中的 !! 与 ~~