理解JS 中相等和全等操作符比较规则

更新日期: 2020-02-06阅读: 1.5k标签: 运算

在日常的 JS 编码过程中,可能很难看到相等运算符(=)是如何工作的。特别是当操作数具有不同类型时。这有时会在条件语句中产生一些难以识别的 bug。很容易理解为什么 0 == 8 是 flase 的或者 '' == false 是 true。但是为什么{} == true是 false 的就看不出来了。接下将会讲这是肿么肥事。

在这之前,先说几个术语:

  • 操作符(Operator) 表示操作的符号。例如,相等运算符==比较两个值,三等运算符 === 比较两个值及其类型,加法运算符+两个数字和或连接两个字符串。
  • 操作数(Operand) 是运算的主体,是执行运算的数量。例如,在表达式 0 == {} 中,0 是第一个操作数,{} 是第二个操作数。
  • JS 中的基本数据类型(原始类型)有 number,string, boolean,null 和 undefined,symbol。


全等运算符 ===

全等和不全等操作符遵循以下基本规则(IEA规则):

  1. 如果两个操作数有不同的类型,它们不是严格相等的
  2. 如果两个操作数都为 null,则它们是严格相等的
  3. 如果两个操作数都为 undefined,它们是严格相等的
  4. 如果一个或两个操作数都是 NaN,它们就不是严格相等的
  5. 如果两个操作数都为 true 或都为 false,它们是严格相等的
  6. 如果两个操作数都是 number 类型并且具有相同的值,则它们是严格相等的
  7. 如果两个操作数都是 string 类型并且具有相同的值,则它们是严格相等的
  8. 如果两个操作数都引用相同的对象或函数,则它们是严格相等的
  9. 以下所有其他情况下操作数都不是严格相等的。

规则很简单。

值得一提的是,在全等运算中,NaN 与其他任何值相比,结果都是 false。 来看看考虑些例子,这是学习这些规则的好方式。

例 1

1 === "1" // false, 规则 1

操作数是不同的类型(数字和字符串),基于 IEA 规则1,它们是不等的。

例 2

0 === 0 // true, 规则 6

操作数具有相同的类型和相同的值,因此根据IEA规则6,它们是严格相等的。

例 3

undefined === undefined // true, 规则 3

两个操作数都是 undefined 的,应用 IEA 规则3,它们是相等的。

例 4

undefined === null // false, 规则 1

因为操作数是不同的类型,根据IEA规则1,它们并不相同。

例 5

NaN === NaN // false, IEA 规则 5

操作数是相同的类型,但是IEA 规则4 表明任何与 NaN 比较都是不相等的。

例 6

var firstObject = {},
  secondObject = firstObject;
secondObject['name'] = 'Neo';
secondObject === firstObject // true, IEA 规则 8

两个变量 firstObject 和 secondObject 都是对同一对象的引用,根据 IEA 规则8,它们相等。

例 7

[] === [] //false, IEA 规则 9

字面量 [] 创建了一个新的数组引用。这两个操作数是相同的类型(对象),但是它们引用不同的对象。根据 IEA 规则 9 ,它们不相等。


对象转换为原始值的规则

对象到布尔值

对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为 true。对于包装对象亦是如此:new Boolean(false) 是一个对象而不是原始值,它将转换为 true。

对象到字符串

对象到字符串 和 对象到数字 的转换都是通过调用待转换对象的一个方法来完成的。一个麻烦的事实是,JS 对象有两个不同的方法来执行转换,接下来要讨论的一些特殊场景更加复杂。值得注意的是,这里提到的字符串和对象的转换规则只适用于原生对象(native object)。宿主对象(例如有Web浏览器定义的对象)根据各自的算法可以转换成字符串和数字。

所有的对象继承了两个转换方法。第一个是toString(),它的作用是返回一个反映这个对象的字符串。默认的 toString() 方法并不会返回一个有趣的值:

({x:1,y:2}).toString()  //=>"[object object]"

很多类定义了更多特定版本的toString()方法。例如,数组的 toString() 方法是将每个数组元素转换为一个字符串,并在元素之间添加逗号后合并成结果字符串。

函数的 toString() 方法返回了这个函数的实现定义。实际上,这里的实现是通常是将用户定义的函数转换为 JS 源代码字符串。

日期 Date 的 toString() 方法返回了一个可读的日期和时间字符串。

RegExp 的 toString() 方法将RegExp对象转换为表示正则表达式直接量的字符串:

来几个例子:

[1,2,3].toString() //=> "1,2,3"
(function(x){ f(x); }).toString() // => "function(x){ f(x); }"
/\d+/g.toString()   // => "/\d+/g"
new Date(2019,9,16).toString()  //=> "Wed Oct 16 2019 00:00:00 GMT+0800 (中国标准时间)"

另一个转换对象的函数是 valueOf()。如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的 valueOf() 方法简单地返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个方法,调用这些类型的实例的valueOf() 方法只是简单返回对象本身。日期 Date 的 valueOf() 方法会返回它的一个内部表示:1970年1月1日以来的毫秒数。

new Date(2019,9,16).valueOf() // 1571155200000

通过使用 toString() 和 valueOf() 方法,就可以做到对象到字符串和对象到数字的转换了。但需要注意的是,在某些特殊的场景中,JS 执行了完全不同的对象到原始值的转换。

JS 中对象到字符串的转换经过如下这些步骤,咱们简称 OPCA 算法。

  1. 如果方法 valueOf() 存在,则调用它。如果 valueOf() 返回一个原始值,JS 将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。
  2. 如果方法 toString() 存在,则调用它。如果 toString() 返回一个原始值,JS 将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。需要注意,原始值到字符串的转换。
  3. 否则,JS 无法从 toString() 或 valueOf() 获得一个原始值,它将抛出一个 TypeError:不能将对象转换为原始值 异常

当调用 valueOf() 方法时,大多数原生对象都会返回对象本身。因此 toString() 方法使用得更频繁。

关于 Date 对象的注意事项:在转换为原始值时,对象立即使用 toString() 方法转换为字符串。这样,规则1就被跳过了。普通的 JS 对象,{}或 new object(),通常被转换成 "[object Object]"

数组通过将它的元素与“,”分隔符连接转换为。例如 [1,3,"four"] 被转换成" 1,3,four"。


相等运算符 ==

相等运算符 “==” 如果两个操作数不是同一类型,那么相等运算符会尝试一些类型转换,然后进行比较。

相等运算符算法(EEA)

  1. 如果操作数具有相同的类型,请使用上面的 IEA 测试它们是否严格相等。 如果它们不严格相等,则它们不相等,否则相等。
  2. 如果操作数有不同的类型:
    2.1如果一个操作数为 null 而另一个 undefined,则它们相等
    2.2如果一个值是数字,另一个是字符串,先将字符串转换为数字,然后使用转换后的值比较
    2.3如果一个操作数是布尔值,则将 true 转换为 1,将 false 转换为 0,然后使用转换后的值比较
    2.4如果一个操作数是一个对象,而另一个操作数是一个数字或字符串,则使用OPCA将该对象转换为原原始值,再使用转换后的值比较
  3. 在以上的其他情况下,操作数都不相等

例 1

1 == true // true

上面的转换步骤:

  1. 1 == true (使用EEA 规则2.3 将 true 转换为 1)
  2. 1 == 1(操作数有相同的类型。使用 EEA 规则1 将相等转换为全等运算进行比较
  3. 1 === 1(两个操作数都是数字,并且具有相同的值。根据 IEA 规则 6,这是相等的)
  4. true

例 2

'' == 0 // true

上面的转换步骤:

  1. '' == 0(一个操作数是字符串,另一个操作数是数字,根据EEA规则2.2,'' 被转换为数字 0 )
  2. 0 == 0(操作数类型相同,使用 EEA规则1 将相等转换为全等运算进行比较)
  3. 0 === 0(操作数类型相同,值相同,所以根据IEA规则6,它是一个恒等式)
  4. true

例 3

null == 0 // false

上面的转换步骤:

  1. null == 0 (null 是原始类型,0 是 number 类型。根据EEA规则3)
  2. false

例 4

null == undefined // true

上面的转换步骤:

  1. null == undefined(基于EEA规则2.1,操作数相等)
  2. true

例 5

NaN == NaN // false

上面的转换步骤:

  1. NaN == NaN(两个操作数都是数字。根据EEA规则1,将相等转换为全等运算进行比较)
  2. NaN === NaN(根据IEA规则4,操作数严格不相等)
  3. false

例 6

[''] == '' // true

上面的转换步骤:

  1. [''] == ''(['']是一个数组和 '' 是一个字符串。应用EEA规则2.4并使用OPCA规则2将数组转换为原始值 '')
  2. '' == '' (两个操作数都是字符串,将相等转换为全等运算进行比较)
  3. '' === '' (两个操作数类型相同,值相同。使用IEA规则7,它们是相等的)
  4. true

例 7

{} == true // false

上面的转换步骤:

  1. {} == true(使用EEA规则2.3,将 true 操作数转换为 1)
  2. {} == 1(第一个操作数是一个对象,因此有必要使用OPCA将其转换为原始值)
  3. “[object object]”== 1(因为第一个操作数是字符串,第二个操作数是数字,根据 EEA规则2.2 将“[object object]”转换为数字)
  4. NaN == 1(两个操作数都是数字,因此使用 EEA规则1 将相等转换为全等运算进行比较)
  5. NaN === 1(根据 IEA规则4,没有什么是与 NaN 相等的,结果是 false)
  6. false


实用技巧

即使在详细研究了本文中的所有示例、学习了算法之后,你会发现要立即理解复杂的比较还需要时间的积累。

告诉你一些技巧。 将本文添加到书签中(使用Ctrl + D),下一次看到有趣的情况时,可以根据等式算法编写逐步的计算。 如果检查至少 10 个示例,则以后不会有任何问题。

现在就可以试试,如 [0] == 0 的结果和转化步骤是什么?

相等运算符==进行类型转换。因此,可能会产生意想不到的结果,例如 {}== true 是 false( 参见例7)。在大多数情况下,使用全等操作符 === 更安全。


总结

相等和全等运算符号可能是最常用的运算符之一。理解它们是编写稳定且bug较少的 JS 的步骤之一。

原文:https://dmitripavlutin.com/

链接: https://www.fly63.com/article/detial/8855

js除了Math.floor方法,还可以通过位运算|,>>实现向下取整

我们都知道通过Math.floor()方法可实现数值的向下取整,得到小于或等于该数字的最大整数。除了Math.floor方法,还可以使用位运算|,>>来实现向下取整哦

es6 扩展运算符 三个点(...)

扩展运算符( spread )是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

巧用JS位运算

位运算的方法在其它语言也是一样的,不局限于JS,所以本文提到的位运算也适用于其它语言。位运算是低级的运算操作,所以速度往往也是最快的

js中使用位运算,让执行效率更高

平常的数值运算,其本质都是先转换成二进制再进行运算的,而位运算是直接进行二进制运算,所以原则上位运算的执行效率是比较高的,由于位运算的博大精深,下面通过一些在js中使用位运算的实例

js各种取整方式及方法_四舍五入、向上取整、向下取整

js实现:四舍五入、向上取整、向下取整等方法。parseInt、Math.ceil、Math.round、Math.floor、toFixed等的使用

JavaScript循环计数器

JS经常会遇到延迟执行的动作,并且失败后自动尝试,尝试N次之后就不再尝试的需求,今天刚好又遇到,于是写个闭包,以后不断完善继续复用。检查并计数第一个参数用来标记是尝试哪个动作的,第二个参数是最大尝试次数

js 位运算符_js按位运算符及其妙用

大多数语言都提供了按位运算符,恰当的使用按位运算符有时候会取得的很好的效果。在我看来按位运算符应该有7个:& 按位与、| 按位或、^ 按位异或、~ 按位非

PHP取整、四舍五入取整、向上取整、向下取整、小数截取

PHP取整数函数常用的四种方法:1.直接取整,舍弃小数,保留整数:intval(); 2.四舍五入取整:round(); 3.向上取整,有小数就加1:ceil(); 4.向下取整:floor()。

JavaScript 中的相等操作符 ( 详解 [] == []、[] == ![]、{} == !{} )

ECMAScript 中的相等操作符由两个等于号 ( == ) 表示,如果两个操作数相等,则返回 true。相等操作符会先转换操作数(通常称为强制转型),然后比较它们的相等性。

关于js开发中保留小数位计算函数(以向上取整或向下取整的方式保留小数)

前端工作中经常遇到数字计算保留小数问题,由于不是四舍五入的方式不能使用toFixed函数,本文采用正则表达式匹配字符串的方式,解决对数字的向上或向下保留小数问题:

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!