理解JS中相等和全等操作符⽐较规则
在⽇常的 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合并两个数组对象到字符串
对象到字符串和对象到数字的转换都是通过调⽤待转换对象的⼀个⽅法来完成的。⼀个⿇烦的事实是,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 的步骤之⼀。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论