Skip to content

由 [-a+++b++] 引发的思考 - JavaScript运算符优先级

1295字约4分钟

JavaScript

2025-01-06

前言

最近在写代码的时候,遇到了一个比较有意思的问题,就是关于运算符优先级的问题。具体代码如下:

let a = 1;
let b = 2;
console.log(-a+++b++);

运行结果如下:

1

按照运算符优先级,-a+++b++ 可以拆分为 -(a++) + (b++)。因为 a++b++ 是后置递增运算符,所以 ab 的值在计算时不会改变,从左到右依次计算,所以最终结果为 1

运算符优先级

运算符优先级决定了在表达式中运算符的执行顺序。JavaScript 运算符的优先级从高到低详细如下:

优先级运算符类型结合性语法
1分组 ()-(…)
2成员访问 .从左到右….…
2需要计算的成员访问 []从左到右…[…]
2new(带参数列表)-new … ( … )
2函数调用从左到右… ( … )
2可选链 ?.从左到右?.
3new 无参数列表从右到左new …
4后置递增 ++ 和 后置递减 ---… ++… --
5逻辑非 ! 和 按位非 ~从右到左! …~ …
5一元加法 + 和 一元减法 -从右到左+ …- …
5前置递增 ++ 和 前置递减 --从右到左++ …-- …
5typeofvoiddeleteawait从右到左typeof …void …delete …await …
6幂运算 **从右到左… ** …
7乘法 *、 除法 /、 取余 %从左到右… * …… / …… % …
8加法 +、 减法 -从左到右… + …… - …
9按位左移 <<、 按位右移 >>、 无符号右移 >>>从左到右… << …… << …… >>> …
10小于 <、 小于等于 <=、 大于 >、 大于等于 >=从左到右… < …… <= …… > …… >= …
10ininstanceof从左到右… in …… instanceof …
11相等 ==、 不相等 !=、 严格相等 ===、 严格不相等 !==从左到右… == …… != …… === …… !== …
12按位与 &从左到右… & …
13按位异或 ^从左到右… ^ …
14按位或 |从左到右|
15逻辑与 &&从左到右&&
16逻辑或 ||从左到右||
16合并空值 ??从左到右… ?? …
17条件(三元)运算符 ? :从右到左… ? … : …
18所有赋值运算符从右到左… = …… += …… -= …… **= …… *= …… /= …… %= …… <<= …… >>= …… >>>= …… &= …… ^= …… |= …… &&= …… ||= …… ??= …
19逗号从左到右… , …

运算符示例

  1. 按位非运算符 ~
let a = 5; // 二进制表示为 0000 0000 0000 0000 0000 0000 0000 0101
let result = ~a; // 取反后为 1111 1111 1111 1111 1111 1111 1111 1010
console.log(result); // 输出 -6
  1. 一元加法运算符 + 和 一元减法运算符 -
let a = 5;
let result1 = +a; // 一元加法运算符,结果为 5
let result2 = -a; // 一元减法运算符,结果为 -5
console.log(result1); // 输出 5
console.log(result2); // 输出 -5
  1. void 运算符 void 运算符是 JavaScript 中的一个一元运算符,它的主要作用是计算一个表达式并返回 undefined。
let result = void 0; // 计算表达式 0,并返回 undefined
console.log(result); // 输出: undefined
  1. 按位左移运算符 << 、 按位右移运算符 >> 和 无符号右移运算符 >>>
let a = 5; // 二进制表示为 0000 0000 0000 0000 0000 0000 0000 0101
let result1 = a << 1; // 左移 1 位,结果为 0000 0000 0000 0000 0000 0000 0000 1010,即 10
let result2 = a >> 1; // 右移 1 位,结果为 0000 0000 0000 0000 0000 0000 0000 0010,即 2
let result3 = a >>> 1; // 无符号右移 1 位,结果为 0000 0000 0000 0000 0000 0000 0000 0010,即 2
console.log(result1); // 输出 10
console.log(result2); // 输出 2
console.log(result3); // 输出 2

// 为了演示无符号右移运算符的效果,我们来看一个负数的例子:
let b = -5 // 二进制表示为 1111 1111 1111 1111 1111 1111 1111 1011
let result4 = b << 1; // 左移 1 位,结果为 1111 1111 1111 1111 1111 1111 1111 0110,即 -10
let result5 = b >> 1; // 右移 1 位,结果为 1111 1111 1111 1111 1111 1111 1111 1101,即 -3
let result6 = b >>> 1; // 无符号右移 1 位,结果为 0111 1111 1111 1111 1111 1111 1111 1101,即 2147483645
console.log(result4); // 输出 -10
console.log(result5); // 输出 -3
console.log(result6); // 输出 2147483645
  1. in 和 instanceof 运算符

in 运算符用于检测某个属性是否存在于某个对象中,instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

let obj = { a: 1, b: 2 };
console.log('a' in obj); // 输出 true
console.log('c' in obj); // 输出 false

let arr = [1, 2, 3];
console.log(0 in arr); // 输出 true
console.log(3 in arr); // 输出 false

function Person(name) {
  this.name = name;
}

let person = new Person('Alice');
console.log(person instanceof Person); // 输出 true
console.log(person instanceof Object); // 输出 true
console.log(person instanceof Array); // 输出 false
  1. 按位与运算符 & 、 按位异或运算符 ^ 和 按位或运算符 |
let a = 5; // 二进制表示为 0000 0000 0000 0000 0000 0000 0000 0101
let b = 3; // 二进制表示为 0000 0000 0000 0000 0000 0000 0000 0011

let result1 = a & b; // 按位与运算,结果为 0000 0000 0000 0000 0000 0000 0000 0001,即 1
let result2 = a ^ b; // 按位异或运算,结果为 0000 0000 0000 0000 0000 0000 0000 0110,即 6
let result3 = a | b; // 按位或运算,结果为 0000 0000 0000 0000 0000 0000 0000 0111,即 7

console.log(result1); // 输出 1
console.log(result2); // 输出 6
console.log(result3); // 输出 7
  1. 合并空值运算符 ??

合并空值运算符 ?? 用于返回第一个不为 null 或 undefined 的值。

let a = null;
let b = 0;
let c = 'hello';

let result1 = a ?? b; // 输出 0
let result2 = b ?? c; // 输出 'hello'
let result3 = c ?? a; // 输出 'hello'