Like Sunday, Like Rain - JavaScript运算符优先级
“JavaScript⾥的很多奇技淫巧,都来⾃于对运算符的灵活使⽤。”
说到运算符的优先级,我们往往会想到一张见过无数次却从来没背下来的表。因为没背下来, 所以往往会认为它很简单,只要拿不准的时候去看看就好。我曾经也是这么认为的,直到在一个明媚的下午,我对着这张遍,遇到了几个问题。我才发现我其实并没有把它搞定。
《如晴天,似雨天》希望你也能有一个阳光明媚的下午,来解开心中的这些困惑。
1 运算符基础
我们先看一下完整的JavaScript运算符优先级表(文章最后,移动端锚点链接不好用,手滑下去吧)
这张表说明了两个问题:
1.1 优先级: 优先级高的运算符最先被执行
问题: 1 || 1 ? 2 : 3 ; 答案:2 解析:||的优先级高相当于: (1 || 1 )? 2 : 3 而不是: 1 || (1 ? 2 : 3 )
复制代码
1.2 关联性: 运算符执行时的方向。是从左向右,还是从右向左
问题:+function (){var a = b = 1;}();console.log(b); console.log(a); 答案:1 error解析:赋值从右到左,var a = b = 1所以相当于b = 1;var a = b;那有同学可能会问,为什么不是?var b = 1;var a = b;还记得变量提升吗?var a = b = 1;在变量提升的时候,只会把a去声明,并不会执行赋值中的b。所以要想把b也声明了就需要按照语法 var a=1 , b ;
复制代码
现在我们仔细把优先级的题改一下
1 || fn() && fn()
复制代码
MDN上写的是优先级高的运算符最先被执行,我们都知道 ||是短路的,后边不会执行。那么这个最先被执行的含义是什么呢?
1.3 短路:
- && 运算符的短路(a && b):如果a为假,b就不用执行了
- | | 运算符的短路(a || b):如果a为真,b就不用执行了
问题:1 || fn() && fn() 答案:1 fn不会执行解析:就是利用&&运算符的短路原理啊。
复制代码
讲到这有些同学会觉得很简单啊,就是这样啊,看到短路后边就不用算了啊。也有的同学可能会有点懵,不是说好了, 优先级高的先被执行吗?明明&&的优先级高啊。哈哈,别吵吵,我们一起看下一题。
问题:var a = 42;var b = "foo";var c = 0;c || b ? a : b ; // 42复制代码
刚才说短路的同学可能会说还是要参考优先级。刚才说优先级的同学可能一脸懵逼,静静地不想说话。那么我们开始今天的学习吧。
2 绑定
定义:运算符的优先级高先执行,并不是真正的执行,而是更强的绑定。
我们用上面来两个问题
1 || fn() && fn() // &&的优先级高,所以将后边的绑定1 ||(fn() && fn()) // 所以相当于1 和(fn() && fn())的值去逻辑或1 ||(fn() && fn()) // 我们查表,逻辑或从左到右执行。1 ||(fn() && fn()) // 左执行,1是真值,所以短路,后边不执行
复制代码
问题: var a = 42;var b = "foo";var c = 0;c || b ? a : b ; 答案:42解析:c || b ? a : b ; //查表 条件运算符权重是4,逻辑与符权重是6,所以逻辑与有更强的绑定(c || b )? a : b ; //(c || b )相当于条件运算符里的条件(c || b )? a : b ; //(c || b )值是0 ,所以值是 a
复制代码
好,我们在做两题巩固一下
问题: var a = 5;var b = 5;var c = 5+a+++b;[ a , c ]答案: [6, 15]解析: b = 5+a+++b; //查表 后置递增权重17 前置递增权重16b = 5 +(a++)+ b; //++优先级更高,所以和绑定a绑定在一起b = 5 +(a++)+ b; //根据语法后置递增先执行语句,后递增b = 5 +(a++)+ b; //执行语句时a是5,所以b是15b = 5 +(a++)+ b; //a在进行自增,得到6
复制代码
问题: var a = 5;var b = 5;var c = ++a-b;[ a , c ]答案: [6, 1]解析: var c = ++a-b; //查表 前置递增权重和一元减权重都是16,从左往右执行var c = ++a-b; //根据语法前置递增先递增,后执行语句 a = 6var c = ++a-b; //执行语句时a是6,所以b是1
复制代码
看到这,同学们可能恍然大悟,就这么回事啊。别急,我们来看下一题。 要解决这个问题,需要我们理解下一节的概念。
问题: var a = 42;var b = "foo";var c = 0;a && b || c ? c || b ? a : c && b : a
复制代码
3 关联
定义:运算符的关联性去定义表达式的处理方向
来,用题说话
问题:a && b && c 的执行顺序解析:(1)两个运算符都是&&,权重一样。所以这个时候就要看关联性。(2)查表 &&的关联性是从左到右(3)所以表达式应该是 ( a && b ) && c
复制代码
问题:a ? b :c ? d : e 的执行顺序解析:(1)两个运算符都是条件运算符,权重一样。所以这个时候就要看关联性。(2)查表条件运算符的关联性是从右到左(3)所以表达式应该是 a ? b :(c ? d : e )
复制代码
好了,现在我们就可以轻松解决上面那个问题啦。
问题: var a = 42;var b = "foo";var c = 0;a && b || c ? c || b ? a : c && b : a 答案: 42解析:(a && b) || c ? c || b ? a :(c && b) : a //首先查表逻辑与权重是6最高((a && b) || c) ? c || b ? a :(c && b) : a //然后是逻辑或((a && b) || c) ? (c || b ? a :(c && b)) : a //两个条件运算符,权重一样。关联性从右到左复制代码
啊、、有没有很开心 最后的最后,我们来讲一个释疑
4 释疑
哈哈,释疑顾名思义就是解释调疑惑的地方,那最好的办法就是加()。
如果你能够熟练运用优先级/关联的规则,你的代码能更简洁,许多框架都是这样写的,非常漂亮。
但是你要叫不准,那就加()吧,千万别逞能,美其名曰有助于代码的可阅读性。
优先级 | 运算类型 | 关联性 | 运算符 |
---|---|---|---|
20 | 圆括号 | n/a | ( … ) |
19 | 成员访问 | 从左到右 | … . … |
需计算的成员访问 | 从左到右 | … [ … ] | |
new (带参数列表) | n/a | new … ( … ) | |
函数调用 | 从左到右 | … ( … ) | |
18 | new (无参数列表) | 从右到左 | new … |
17 | 后置递增(运算符在后) | n/a | … ++ |
后置递减(运算符在后) | … -- | ||
16 | 逻辑非 | 从右到左 | ! … |
按位非 | ~ … | ||
一元加法 | + … | ||
一元减法 | - … | ||
前置递增 | ++ … | ||
前置递减 | -- … | ||
typeof | typeof … | ||
void | void … | ||
delete | delete … | ||
await | await … | ||
15 | 幂 | 从右到左 | … ** … |
14 | 乘法 | 从左到右 | … * … |
除法 | … / … | ||
取模 | … % … | ||
13 | 加法 | 从左到右 | … + … |
减法 | … - … | ||
12 | 按位左移 | 从左到右 | … << … |
按位右移 | … >> … | ||
无符号右移 | … >>> … | ||
11 | 小于 | 从左到右 | … < … |
小于等于 | … <= … | ||
大于 | … > … | ||
大于等于 | … >= … | ||
in | … in … | ||
instanceof | … instanceof … | ||
10 | 等号 | 从左到右 | … == … |
非等号 | … != … | ||
全等号 | … === … | ||
非全等号 | … !== … | ||
9 | 按位与 | 从左到右 | … & … |
8 | 按位异或 | 从左到右 | … ^ … |
7 | 按位或 | 从左到右 | … | … |
6 | 逻辑与 | 从左到右 | … && … |
5 | 逻辑或 | 从左到右 | … || … |
4 | 条件运算符 | 从右到左 | … ? … : … |
3 | 赋值 | 从右到左 | … = … |
… += … | |||
… -= … | |||
… *= … | |||
… /= … | |||
… %= … | |||
… <<= … | |||
… >>= … | |||
… >>>= … | |||
… &= … | |||
… ^= … | |||
… |= … | |||
2 | yield | 从右到左 | yield … |
yield* | yield* … | ||
1 | 展开运算符 | n/a | ... … |
0 | 逗号 | 从左到右 | … , … |
参考:
MDN运算符优先级
《You Don't Konw JavaScript》
ECMAScript Language: Expressions
Like Sunday, Like Rain - JavaScript运算符优先级相关推荐
- javascript 运算符优先级
JavaScript 运算符优先级(从高到低) https://github.com/xhlwill/blog/issues/16 今天把js函数转换为python 函数时,发现在js运算符优先级这边 ...
- JavaScript基础05-day07【条件运算符、运算符优先级、代码块、if语句】
学习地址: 谷粒学院---尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版J ...
- javascript中基本包装、算数运算符、递增递减运算符、赋值运算符、比较运算符、逻辑运算符、运算符优先级
基本包装类型: 指基本类型的数据变量通过调用属性或者方法包装成了复杂类型,这个变量也称为基本包装类型对象 <script>var str = 'hello';str = str.repla ...
- JavaScript运算符的优先级(案例讲解)
先来看看这道题... 下边代码输出的结果是( ) var val = 'smtg'; console.log('Value is ' + (val === 'smtg') ? 'Something' ...
- JavaScript阴沟里翻船之运算符优先级
首先欢迎大家关注我的Github博客,也算是对我的一点鼓励,毕竟写东西没法变现,坚持下去也是靠的是自己的热情和大家的鼓励.各位读者的Star是激励我前进的动力,请不要吝惜. 起源 写了两年的 ...
- JavaScript:赋值运算符以及运算符优先级
JavaScript前文回顾: 认识JavaScript到初体验 JavaScript 注释以及输入输出语句 JavaScript变量的使用.语法扩展.命名规范 JavaScript数据类型简介以及简 ...
- JavaScript 赋值运算符 、运算符 优先级
赋值运算符 = 直接赋值 += .-= 加减一个数后再赋值 *=./=.%= 乘 除 取模 后在赋值 <script>var m =2;m += 5;console.log(m);// 7 ...
- JavaScript运算符:递增递减运算符前置和后置的区别
从两段代码说起 var num1 = 2; var num2 = 20; var num3 = --num1 + num2; var num4 = num1 + num2; console.log(n ...
- JavaScript(二)—— JavaScript 运算符/JavaScript 流程控制/JavaScript 数组
本篇为 JavaScript 系列笔记第二篇,将陆续更新 文章目录 一.运算符 1. 算术运算符 2. 递增和递减运算符 3. 比较运算符 4. 逻辑运算符 短路运算(逻辑中断) 5. 赋值运算符 6 ...
最新文章
- mina处理断包和粘包
- 中国人民大学_《组织行为学》_16.重塑组织模块导论
- 【科普】一文把数据科学、人工智能与机器学习讲清楚
- SAP Spartacus 定义在app.module.ts里的providers依赖注入元数据何时得到处理
- vue 时间戳 格式转化(插件化) - 封装篇
- github ssh密钥_如何使用SSH密钥在一台机器上管理多个GitHub帐户
- java运算符使用总结_Java运算符知识点总结
- azure备份存储层分类_如何配置Azure SQL数据库长期保留(LTR)备份
- 力扣上的代码想在本地编译运行?
- 基于FPGA的四轴运动控制IC设计(verilog)
- 写一篇关于乡愁的作文1000字以上
- 如何合理确定线程池的大小
- vue---lodash的使用
- 变现 起航篇! 手把手交你用chatgpt快速生成视频!
- 使用ajax和window.history.pushState无刷新改变页面内容和地址栏URL
- 去哪儿网上海景点数据爬虫分析
- Class Dictionary<K,​V>
- 【游戏杂记】.xp3文件的解包
- 【Excel】排名之成绩并列排名(sumproduct、countif 函数的组合使用方法)
- 机械专业就业与计算机专业待遇,机械类专业毕业五年“薪资”排名,车辆工程“逆袭”!...
热门文章
- 《Android开发从零开始》——31.模拟Http请求
- .net连接mysql中文乱码问题的解决
- Arts 第六周(4/22 ~ 4/28)
- 算法题:I am a student. 转为 student. a am I
- slf4j+log4j在Java中实现日志记录
- 30个要点帮你完成java代码优化
- exit()与_exit()函数的区别(Linux系统中)
- ThreadPool执行异步操作
- Java区间拆分子集求和,对列表中的数字子集求和
- java 快排_秋招|字节跳动Java后台已上岸,发个面经回馈牛油