“Determining whether two variables are equivalent is one of the most important operations in programming.” (确定两个变量是否相等是编程中最重要的操作之一)
——Nicholas Zakas

JavaScript中作比较有两个方式:严格模式(strict comparison 使用三个等号 ===)和概要模式(abstract comparison 使用两个等号 ==),对于他们的意义和行为,本文做一个归纳。

为了避免舍本逐末,学习任何知识应该先从标准的定义开始,下面是这两种比较方式在ECMA262标准中的定义:

严格模式 ===

The Strict Equality Comparison Algorithm(严格相等比较算法)

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:(判断步骤如下,注意次序

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Undefined, return true.
  3. If Type(x) is Null, return true.
  4. If Type(x) is Number, then
    • If x is NaN, return false.
    • If y is NaN, return false.
    • If x is the same Number value as y, return true.
    • If x is +0 and y is −0, return true.
    • If x is −0 and y is +0, return true.
    • Return false.
  5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
  6. If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
  7. Return true if x and y refer to the same object. Otherwise, return false.

概要模式 ==

The Abstract Relational Comparison Algorithm

The comparison x < y, where x and y are values, produces truefalse, or undefined (which indicates that at least one operand is NaN). In addition to x and y the algorithm takes a Boolean flag named LeftFirst as a parameter. The flag is used to control the order in which operations with potentially visible side-effects are performed upon x and y. It is necessary because ECMAScript specifies left to right evaluation of expressions. The default value of LeftFirst is true and indicates that the x parameter corresponds to an expression that occurs to the left of the y parameter’s corresponding expression. If LeftFirst is false, the reverse is the case and operations must be performed upon y before x. Such a comparison is performed as follows:(判断步骤如下,注意次序

  1. If the LeftFirst flag is true, then

    • Let px be the result of calling ToPrimitive(x, hint Number).
    • Let py be the result of calling ToPrimitive(y, hint Number).
  2. Else the order of evaluation needs to be reversed to preserve left to right evaluation
    • Let py be the result of calling ToPrimitive(y, hint Number).
    • Let px be the result of calling ToPrimitive(x, hint Number).
  3. If it is not the case that both Type(px) is String and Type(py) is String, then
    • Let nx be the result of calling ToNumber(px). Because px and py are primitive values evaluation order is not important.
    • Let ny be the result of calling ToNumber(py).
    • If nx is NaN, return undefined.
    • If ny is NaN, return undefined.
    • If nx and ny are the same Number value, return false.
    • If nx is +0 and ny is −0, return false.
    • If nx is −0 and ny is +0, return false.
    • If nx is +∞, return false.
    • If ny is +∞, return true.
    • If ny is −∞, return false.
    • If nx is −∞, return true.
    • If the mathematical value of nx is less than the mathematical value of ny —note that these mathematical values are both finite and not both zero—return true. Otherwise, return false.
  4. Else, both px and py are Strings
    • If py is a prefix of px, return false. (A String value p is a prefix of String value q if q can be the result of concatenating p and some other String r. Note that any String is a prefix of itself, because r may be the empty String.)
    • If px is a prefix of py, return true.
    • Let k be the smallest nonnegative integer such that the character at position k within px is different from the character at position k within py. (There must be such a k, for neither String is a prefix of the other.)
    • Let m be the integer that is the code unit value for the character at position k within px.
    • Let n be the integer that is the code unit value for the character at position k within py.
    • If m < n, return true. Otherwise, return false.

通过定义,可以归纳出下面的特点

    • === 不做类型转换,类型不同的一定不等,返回false;
    • 两个string严格相等表示它们有相同的字符排列、相同的长度和每个位置的字符都相同;
    • 两个number严格相等表示它们有相同的数值,NaN和任何东西都不相等,包括NaN它自己;正负零彼此之间相等;
    • 两个boolean严格相等表示它们同时为true或者同时为false;
    • 两个不同的object在严格和概要比较中都不相等,返回false;
    • 两个object相等唯一的情况是他们引用了相同的object;
  • == 在两边值类型不同的时候,会做如下的转换再严格比较:
    • null == undefined 但是 null !== undefined;
    • 如果有一个操作数是一个数字或布尔值,如果可能,另一个操作数转换为数字;否则,如果其中一个操作数为字符串,如果可能,另一个操作数被转换为字符串;
    • 如果两个操作数都是对象,那会比较对象在内存中的引用是否相同。

根据上面的规则,我们知道:如果在比较时两个变量的类型很重要,就要使用严格比较(===);否则可以使用一般比较(==)。

在JavaScript中,下面的值被当做假(false),除了下面列出的值,都被当做真(true):

  • false
  • null
  • undefined
  • 空字符串 ”
  • 数字 0
  • NaN

分析如下的代码:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12

5=='5'   // true  右边的字符串会被转换为数字,然后进行比较
"1"==true  // true true会先转换成数值 1,然后进行比较
//注意 String 对象和 string字符串不同,String对象一般来说很少使用
vara=newString("foo");
varb=newString("foo");
a==b      //false
a===b     //false
a=="foo"  //true
a==="foo"//false

注意在使用 == 时,在类型不同时,会进行强制类型转换,这个转换的规则十分复杂(上面的特点中有简单的说明,详见 ToPrimitive),不了解规则时,会发现表现十分的奇怪:

JavaScript
1
2
3
4
5
6
7
8
9
10
11

''=='0'   //false
0==''     //true
0=='0'    //true
false=='false'    //false
false=='0'        //true
false==undefined  //false
false==null       //false
null==undefined   //true
' \t\r\n '==0     //true

通过上面的例子可以看出,== 在传递性(即 a == b, a == c 推出 b == c)上是不可靠的,以上例子中如果使用 ===,结果都会是 false。所以建议除非非常清楚自己想要的,一般尽量使用 === 来进行比较

下面介绍与判断相等相关的几个知识:

!! 运算符

注意下面的代码:

JavaScript
1
2

NaN   ===  NaN     //false
!!NaN===!!NaN    //true

我们经常会在代码中看到 !! 运算符,它是一个编程技巧,作用主要是把一个变量或表达式转换为boolean,看下面的代码(均返回 true):

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

!!false===false
!!true===true
!!0===false
!!parseInt("foo")===false// NaN 为 false
!!1===true
!!-1===true
!!""===false//空字符串为false
!!"foo"===true  //非空字符串都为true
!!"false"===true  //非空字符串都为true
!!window.foo===false//undefined为false
!!null===false//null为false
!!{}===true  //空对象为true
!![]===true  //空数组为true
!!newBoolean(false)===true  //这里是个对象
!!Boolean(false)===false     //这里才是boolean值

相类似的快速转换类型写法还有下面的两个:

Number(foo) === +foo
String(foo) === ”+foo

变量和常量的顺序

大家在阅读js资料时可能会发现有这样的写法推荐,即变量放在双等号的右边,常量放在左边:

JavaScript
1
2
3
4
5

//尽量使用
if('0'==a){......
//不要使用
if(a=='0'){......

这是“Yoda表示法”,名字来源于《星球大战》的 Yoda 大师。他说话的单词顺序相当奇特,比如:“Backwards it is, yes!”。

这样写主要是防止缺少等号的笔误,比如把 if ( a == ’0′ ) 误写成了 if ( a = ’0′ ),如果采用了常量在前的判断写法,如果把 if ( ’0′ == a ) 误写成了 if ( ’0′ = a ),则会抛出错误(ReferenceError: Invalid left-hand side in assignment)。

一般来说,作为代码书写规范来说,推荐常量在左进行判断的写法。

转载于:https://www.cnblogs.com/littleCode/p/3709056.html

JavaScript中的两个等号(==)和三个等号(===)相关推荐

  1. JS/JavaScript中两个等号 == 和 三个等号 === 的区别

    JavaScript中两个等号 == 和 三个等号 === 的区别 一.概念 == 和 ===  (1)  "=="叫做相等运算符,"==="叫做严格运算符. ...

  2. js两个等号和三个等号_js中两个等号(==)和三个等号(===)的区别

    js中两个等号(==)和三个等号(===)的区别: 1. "=="表示:equality -> 等同 的意思,"=="使用两个等号时,如果两边值的类型不同 ...

  3. js中两个等号“==“与三个等号“===“有何不同

    一.1个等号"=": 首先一个等号"=",大家都知道,一般在编程语言中是用来做赋值操作的,也叫赋值运算符,即把等号右边的值,赋值给左边声明的变量. 例如:在js ...

  4. java两字符串是否相等_Java与JavaScript中判断两字符串是否相等的区别

    JavaScript是一种常用的脚本语言,这也决定了其相对于其他编程语言显得并不是很规范.在JavaScript中判断两字符串是否相等 直接用==,这与C++里的String类一样.而Java里的等号 ...

  5. 两个等号(==)和三个等号(===)的区别

    2019独角兽企业重金招聘Python工程师标准>>> 两个等号(==)和三个等号(===)的区别: 1. "=="表示:equality -> 等同 的意 ...

  6. 网页html怎么调整字样,怎么在css中设置两个字和三个字对齐

    怎么在css中设置两个字和三个字对齐 发布时间:2021-03-09 15:16:12 来源:亿速云 阅读:85 作者:Leah 怎么在css中设置两个字和三个字对齐?针对这个问题,这篇文章详细介绍了 ...

  7. 如何在 JavaScript 中比较两个日期?

    平等比较 在大多数情况下,不建议使用松散或严格的相等运算符 ( ==or )在 JavaScript 中比较两个日期.===等式运算符比较Date对象引用,false即使日期值相同,也会产生 : co ...

  8. js中两个等号和三个等号区别?

    == equality 等同,=== identity 恒等.==, 两边值类型不同的时候,要先进行类型转换,再比较. ==,不做类型转换,类型不同的一定不等.下面分别说明: 先说 ===,这个比较简 ...

  9. Js中两个等号(==)和三个等号(===)的区别

    1. "=="表示:equality ->等同的意思,"=="使用两个等号时,如果两边值的类型不同的时候,是要先进行类型转换后,才能做比较 2. &quo ...

最新文章

  1. java定时任务框架elasticjob详解
  2. matlab柱状斜线_Matlab小练习:按斜线方向依次赋值矩阵
  3. 解析JVM内存区域组成
  4. STM32工作笔记0059---独立看门狗实验
  5. python appium api pc_Appium Python API 中文版
  6. 寫程式不需要天份,也不需要熱情
  7. 排序(python)
  8. listview复用机制研究
  9. 2021.9.11周六PAT甲级考试复盘与总结
  10. HTML页面跳转的方法
  11. 什么是JavaSE,写给第一次接触Java的人
  12. 串口数据接收、发送与USB转串口驱动下载
  13. Pandas 筛选数据的 8 个神操作
  14. 重读《从菜鸟到测试架构师》-- 开发团队做的远不仅是开发
  15. 关于1NF、2NF、3NF、BCNF的常考判定
  16. SSM框架学习——Maven进阶学习
  17. 一元多项式因式分解的唯一性定理
  18. git-cz 规范提交代码注释
  19. 北京35岁程序员失业,感叹:编程估计没戏了,想去卖点煎饼果子养家~
  20. 工作流初始错误 泛微提交流程提示_泛微OA用户操作手册.pdf

热门文章

  1. VisualStudio安装
  2. jquery-file-upload限制文件上传大小和文件个数
  3. 怎样在ppt中加入随机抽号_潮流女生怎样穿更时髦?经典中加入个性,减龄时尚还高级,快入坑...
  4. java的隐藏函数_java – 隐藏子级数据成员的父成员函数
  5. 测试化验加工费云服务器文献信息,监管▕ 科研经费使用中的 “红线”和“禁区”典型问题自查清单...
  6. 小波变换原理_基于电压行波原理故障测距的相关问题
  7. python矩阵赋值提高速度_Numpy大规模矩阵运算优化加速技巧
  8. 怎么查到运行的时间_“我的成考录取通知书怎么还没来,它是不是迷路了?”...
  9. linux的常用的软件,Linux常用的软件和命令
  10. linux-headers,如何升级linux-headers-generic?