Array|从面试考察运算符优先级谈编码规范和管理

前几天在网上看到一篇文章 , 说是作者在面试中被问到 , javascript语言代码“true || false && false”的结果是什么以及具体的原因 。看了那个文章以后 , 我特意上网查了一下 , 发现讨论这个问题的类似文章非常多 , 最早的同题材文章似乎是2016年发表的 。其中一篇文章特别有意思 , 作者先是根据“true || false && false”的结果 , 推测出&&运算符的优先级高于||运算符 。这个结论应该说是对的 。其实 , 这在MDN的javascript运算符优先级表就已经明确说明了 。但作者还做了进一步的实验 , 分别是“true || alert(2) && false”和“false && false || alert(1)” 。前者的alert(2)不会执行 , 作者觉得颠覆了自己之前关于优先级的结论 。后者的alert(1)会执行 , 作者又觉得这与&&和||优先级相同且逻辑短路的假设有冲突 。最后 , 作者从实际结果出发和一个做JAVA的同事讨论后 , 推导出一个结论:“遇到||运算符 , 先去左边的表达式得出结果 , 如果结果为true , 则不会去执行右边的表达式 , 则短路运算生效;如果结果为false , 则去执行右边的表达式 , 再去根据两边的结果去执行||运算符” 。作者的这个结论既可以说正确 , 也可以说不正确 。因为 , 这个结论只是对一种特例的描述 。就好像经典牛顿力学与相对论力学的关系的一样 。靠近通用原理的解释是:运算符的优先级约束的是运算发生的顺序 , 不约束操作数被取值的顺序;没有特殊约定时 , 双目运算符总按照自左向右取操作数;当运算符为逻辑运算符时 , 左操作数取值完成后 , 经由逻辑短路原则判断后 , 再评估是否实际进行取右操作数;多运算符存在的长表达式中 , 操作数的取值过程按照语句生成的语法树的前序遍历原则确定顺序 。
这里 , 我不是想讨论语言和编译技术的内容 。我是想谈谈 , 考察具体语言中运算符优先级顺序这类的知识 , 到底有多少意义 。我们先看一下javascript中的运算符优先级总表:
Array|从面试考察运算符优先级谈编码规范和管理
文章图片

文章图片

(摘自MDN)
javascript的运算符多达60个 , 优先级多达20级 。你们确定自己能够一字不落的记忆下来?你们确定愿意去记忆这么多的内容?至少我是不愿意的 。背诵优先级能够解决的问题 , 我用“()”强制标注优先级就能解决了 。我会更愿意将“true || false && false”这条语句写成“true || (false && false)” 。这样 , 不仅我自己不容易出现失误 , 看我代码的人也不需要记忆一堆的优先级 , 就能准确无误看懂我的代码 。
或许有人会提出 , "()"本质也是运算符 , 加了太多“()”是不是会影响代码运行效率 。对于这个疑问 , 只能说是多虑了 。现代的编译器 , 都能在代码优化阶段根据优先级自动脱去不需要的“()” 。即便是作为解释型语言的javascript , 也有babel这样的处理工具 , 可以对代码进行类似编译的处理 , 脱去多余的运算符 。比如下面的代码:
Array|从面试考察运算符优先级谈编码规范和管理
文章图片

文章图片

(未经过babel处理的代码)
通过babel进行处理 , 可以得到下面的结果:
Array|从面试考察运算符优先级谈编码规范和管理
文章图片

文章图片

(babel处理后的代码脱去了多余的括号)
写代码的目的 , 是开发出一个产品 。在计算机技术发展的“远古”时期 , 由于编译器之类工具的能力不强 , 开发人员通过自身对语言细节的深入掌握来优化代码效率是必要的 。今时今日 , 软件开发的各种辅助工具的能力已经得到了极大提高 , 大大释放了开发人员在低价值信息上的记忆压力和劳动力 , 在代码编写上的“炫技”已经难以让你的产品变得更优秀 。怎样让代码编写的失误率降低 , 进而提升产品的质量和交付速度 , 对做好一个产品来说更加有价值 。所以 , 与其在面试的时候花力气考察应聘者对优先级的记忆 , 或者培训你的下属在代码语法细节上的深入 , 不如制定一个更有效的编码规范 。编码规范的意义不仅是从排版格式和命名等方面让代码协作开发时更易于阅读 , 更重要的是通过一系列的约定 , 将优秀经验固化下来 , 让大量的开发者能够快速接受前人的经验减少失误 。


推荐阅读