一、短路运算
当逻辑与&&
的第一个操作数的值是false
时,直接返回第一个操作数的值,不再对第二个操作数进行计算
当逻辑或||
的第一个操作数的值是true
时,直接返回第一个操作数的值,不再对第二个操作数进行计算
二、运算符优先级
三、求值顺序
1 | function fn01() { |
要注意区分优先级
、结合性
、求值顺序
三者的区别。
这三个是不同的概念,却经常被混淆。通过AST
来看就很容易理解:(假设源码是从左到右输入的)
所谓优先级,就是不同操作相邻出现时,AST节点与根的距离的关系。优先级高的操作会更远离根,优先级低的操作会更接近根。为什么?因为整棵AST是以后序遍历求值
的,显然节点离根越远就越早被求值。
所谓结合性,就是当同类操作相邻出现时,操作的先后顺序同AST节点与根的距离的关系。如果是左结合,则先出现的操作对应的AST节点比后出现的操作的节点离根更远;换句话说,先出现的节点会是后出现节点的子节点。
所谓求值顺序,就是在遍历子节点时的顺序。对二元运算对应的节点来说,先遍历左子节点再遍历右子节点就是从左到右的求值顺序,反之则是从右到左的求值顺序。
这三个概念与运算的联系都很紧密,但实际描述的是不同的关系。前两者是解析器根据语法生成AST时就已经决定好的,后者则是解释执行或者生成代码而去遍历AST时决定的。
在没有副作用的环境中,给定优先级与结合性,则无论求值顺序是怎样的都能得到同样的结果;而在有副作用的环境中,求值顺序会影响结果。
对应console.log(fn01() || fn02() && fn03())
,AST是:
1 | || |
表达式层面上,代码的执行就是后序遍历这棵AST而已。
优先级:在相邻的两个运算符 || 与 && 中,&& 比 || 离AST的根更远所以优先级更高
结合性:这里没有相邻的同优先级运算符所以展现不出 || 与 && 的结合性,虽然它们都是左结合的
求值顺序:JavaScript的求值顺序就是从左向右的。对这棵AST来说就是在后序遍历时,每个节点的求值过程是先遍历左子树,再遍历右子树,然后对自己求值。
AST生成传送门