【从源码探秘到JS基础】运算符优先级和结合性

129 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

前言

近期回顾了一下JS中运算符的优先级、结合性和表达式的执行顺序的知识,也算是受益匪浅,也就来分享分享成果~~~

先从题目入手吧

  1. let x = true || false && false
    console.log(x);    			    // true
    
  2. var x = 3
    console.log(x ** 1 ** 2)         // 3
    
  3. var a = 1;
    function fun() {
        a = 2;
        return 3;
    }
    var b = fun() + a * 2;
    console.log(b);                 // 7
    

上面3道题目你能否完全理解和答对喃~~~,如果不能那还不看看下面的解答!!!

优先级

这个概念其实很容易理解,我们在小学时一定听过先乘除,后加减的运算口诀,其实这里面就已经包含了运算符优先级的知识~~~

  • 乘除运算符的优先级高于加减运算符
  • 表达式中操作多个运算符时,优先级高的运算符会被优先执行
console.log(3 + 10 * 2);      // 23

重新看看上面的第①题

let x = true || false && false
console.log(x);                       // true

查询JS运算符优先级的对照表,可以知道*&&运算符的优先级是大于||*运算符的

let x = true || false && false
// 等价于
let x = true || (false && false)      // true

联合

圆括号运算符的优先级是所以运算符中最高的,可以用于包裹表达式和子表达式让低优先级的表达式优先执行

使用圆括号运算符包裹表达式和子表达式,也可以称这样的方式称为联合

console.log((3 + 10) * 2);    // 26

结合性

优先级解决的是不同优先级的运算符,那如果相同优先级的运算符喃?

可以参考一下题目②

var x = 3
console.log(x ** 1 ** 2)

这里就要谈论到处理同一优先级的运算符之间的执行顺序了,这也就是运算符的结合性

结合性可以分为两种:一种是左结合,另一种是右结合


let a = 1 + 2 - 3
// 等价于
let a = (1 + 2) - 3

很多朋友看到上面的代码,可能会觉得对于同一优先级的运算符,不就应该从左到右依次执行嘛

那再看看下面这个例子

let a = 2 ** 1 ** 2

如果按照上面从左到右依次执行的规则,那是不是应该就这样执行

let a = (2 ** 1) ** 2     // 64

但是我们在控制台执行上面的表达式得到就结果不是64,而是512,这说明左到右依次执行的规则不是符合所以运算符的!!!

而上面表达式的执行顺序应该是:

let a = 2 ** (3 ** 2)    // 512

这里也就解答了题目②

总结上面两种执行方式,从左到右的叫做左结合,而从右向左联合的叫做右结合


赋值运算符是最常见右结合运算符

(function () {
    var a = b = 2
})()
console.log(a, b)		// undefined   2

var a = b = 2会怎样执行喃?

首先都是赋值运算符,说明优先级是一样的,那就要根据结合性了,我们知道赋值运算符是右结合,所以就得按照如下执行

var a = (b = 2)

因为执行b = 2没有蹭到var的声明,使用b赋值到了全局window上,成为了全局变量

开发所需注意点

在我们日常开发中,运算符那么多,如果每次使用运算符,都要去了解它的优先级,那对于开发来说也是一种痛苦!!!

我们可以通过联合的方式,让代码按照我们所需要的顺序去执行,这对于开发是百利无害的!!!

为了不出现表达式优先级和结合性的BUG,多用联合处理运算符的执行顺序

执行顺序

运算符的优先级处理不同的运算符合和操作数的联合

运算符的结合性处理相同的运算符合和操作数的联合

所以通过优先级和结合性已经能确定运算符和操作数之间的关系,但是在运行时始终要坚持求值顺序总是从左到右

function echo(num) {
    console.log("操作数:" + num);
    return num;
}
console.log(echo(3) + echo(10) * echo(2))     // 23
// 等价于
console.log(echo(3) + (echo(10) * echo(2)))

输出:

操作数:3
操作数:10
操作数:2
23

可以看到就算*echo(10) * echo(2)*的优先级很高,但是表达式的执行顺序还是从左向右的

这里再去回顾一下第③题,是不是就很简单喃!!!


这里再给一个JS的关于执行顺序的经典面试题

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 }
console.log(a.x);            // undefined 
console.log(b);              // {n: 1, x: {n: 2}}

这里你答对了吗?