JavaScript中的两个等号(==)和三个等号(===)

“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)。

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

时间: 2024-11-03 21:08:36

JavaScript中的两个等号(==)和三个等号(===)的相关文章

JavaScript中的两种事件流

JavaScript中的两种事件流 事件流描述的是从页面中接收事件的顺序.提出事件流概念的正是IE和Netscape,但是前者提出的是我们常用的事件冒泡流,而后者提出的是事件捕获流. 第一部分:事件冒泡 即事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档). 下面举一个简单的例子: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"&

JavaScript中的两个“0”(翻译)

本文翻译自JavaScript’s two zeros JavaScript has two zeros: −0 and +0. This post explains why that is and where it matters in practice. JavaScript 中有两个“0”: -0 和 +0 .这篇文章解释了为什么,并且指出实际生产中会造成什么影响 1.The signed zero 1.“-0” Numbers always need to be encoded to b

JavaScript中的两个“0” -0和+0

JavaScript中的两个"0"(翻译) 本文翻译自JavaScript's two zeros JavaScript has two zeros: ?0 and +0. This post explains why that is and where it matters in practice. JavaScript 中有两个"0": -0 和 +0 .这篇文章解释了为什么,并且指出实际生产中会造成什么影响 1.The signed zero 1."

javascript中对两个对象进行排序 和 java中的两个对象排序

javascript中的对象数组排序 一 定义一个对象数组 var text = [{"name":"张","age":24},{"name":"秦","age":26},{"name":"刘","age":29},{"name":"司空","age":78},{&qu

javascript中对象两种创建方式

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> // 创建对象的两种方式: // 1 对象字面量 // 2 new Obj

JavaScript中交换两个变量的值得三种做法(代码实现)

javascript在编程时经常会涉及到如何交换两个变量的值,例如常见的冒泡排序,快速排序等:下面我讲根据自己近期所学总结几种常见的交换两个变量值的方法: 方法一:借助第三方变量交换两个变量的值 var num1=20; var num2=50; var temp=num1; num1=num2; num2=temp; console.log(num1);//在控制台输出交换后的num1=50 console.log(num2);//在控制台输出交换后的num2=20 方法二:借助加法计算,交换

js 中 ==与===区别(两个等号与三个等号)

1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较"转化成同一类型后的值"看"值"是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进行"值"比较,两者结果一样 2.对于Array,Object等高级类型,==和===是没有区别的 进行"指针地址"比较 3.基础类型与高级类型,==和===是有区别的 1)对于==,将高级转化为基础类型,进行"值&quo

js ==与===区别(两个等号与三个等号)

1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进行“值”比较,两者结果一样 2.对于Array,Object等高级类型,==和===是没有区别的 进行“指针地址”比较 3.基础类型与高级类型,==和===是有区别的 1)对于==,将高级转化为基础类型,进行“值”比较 2)因为类型不同,===结果为false

js ==与===区别(两个等号与三个等号

1.对于string,number等基础类型,==和===是有区别的 1)不同类型间比较,==之比较"转化成同一类型后的值"看"值"是否相等,===如果类型不同,其结果就是不等 2)同类型比较,直接进行"值"比较,两者结果一样 2.对于Array,Object等高级类型,==和===是没有区别的 进行"指针地址"比较 3.基础类型与高级类型,==和===是有区别的 1)对于==,将高级转化为基础类型,进行"值&quo