经常有朋友邮件过来咨询技术问题,本人不才经常不是忘记回复就是回复的比较迟。原因是一来本人比较懒(或者可以托词为忙),二来是怕「误人子弟」。

当回复这位仁兄的邮件时,不觉得就发现回复的字数越来越长,于是就将其整理为篇 Blog。我的意图是不仅仅帮忙解决问题,而且能提供个解决类似问题的思路。

邮件原文

来自: Captain
时间: 2010-02-28 20:41
话题: 新手虚心求教

  你好,我是刚刚入门学习Javascript的新手。我想向你请教一下我在学习过程中所
遇到的一个问题。恕我愚昧,但是我一直无法理解,恳请赐教。 
  我在学习中碰到过一条这样的声明: var !myVariable != variableValue, 因为在
以前的学习中知道双重否定等于可定,那这则声明是否可以理解成 var myVariable = 
variableValue ?
       若非如此解释,恳求正解。冒昧打扰请多多包涵。

我的回复

不好意思,收到你的来信到现在才回复。第一眼看见您提供的代码,个人觉得它不合乎语法规则

var !myVariable != variableValue

根据 ECMA 相关的文档,var 关键字的定义在 12.2 章节(我看的是第五版),它的语法定义是:

var VariableDeclarationList ;

而 VariableDeclarationList 包括

VariableDeclarationList , VariableDeclaration

上述两个定义又包含多种情况,说起来有些复杂,所以我画了张草图(可能不准确,以文档为准):

https://friable.rocks/_/2010_03_10/1268192678.png

所以,上面的表达式不符合 var 语句的定义要求,因此 Javascript 解析器会报语法错误。

如果是非赋值定义语句,也就是

!myVariable != variableValue

那么就是个条件判断语句,其中有两个条件判断操作符「非(!)」以及「不等于(!=)」,那么我们就要了解它们的结合优先级。

根据相关的参考文档 ,我们可以得知「非」操作符的优先级比「不等于」要高,因此语句先计算 !myVariable 这块,然后再计算「不等于」后的值。

至于能否改成其他等同的逻辑情况,这里还有个问题就是 值取「非」的时候会有多种情况 ,这里有个讨论:

明城: 
问: !a != b 是否等于 b == !!a

崇厚: 
这个还要看数据类型吧?
比较运算符的优先级是最低的

渔隐: 
照这样推理就是a == b 了

崇厚: 
a = ''
b = 0
console.log(!a != b)
console.log(b == !!a)
true true

明城: 
关键还有个「非」操作符,所以 B 始终是和布尔值对比的

崇厚: 
我试出来三个结果
t t 
t f
f f

痴灵: 
var a = 0;
console.log(!a);console.log(typeof(!a),typeof(a));
true boolean number
类型发生了变化了

渔隐: 
用!== 和===吧

明城: 
不纠结了,以后记得逻辑表达式里千万不要加一元操作符
或者加括号

沉鱼: 
有个比较有效的做法,不太记得操作符的优先级时,我都
加(),这样虽然比较挫,不过保险

崇厚: 
不管记得不记得优先级,表达式比较复杂时最好都加括号
这样看起来清晰一些

举一反三,以后如果再碰到类似的问题,我们可以:

  1. 查文档。 ECMAScript 规范MDC 中的文档 、甚至 Google 都是我们的好帮手
  2. 如果还是无法理解,可以「偷懒」先看运行结果,然后逆向推断
  3. 团队的力量胜过一个人闭门造车

-- EOF --