舍小利而求大利
按照正常逻辑,我们在判断两个值是否相等时会遵循以下规则:
但是我看了下面的一组值:
[]==0 //true[]==false //true[]==!{ }//true[10]==10//true ' 0 '==false//true ' '==0//true undefined==null//true!Null==true //true没有遵循我们的脚本,那么它的规则是什么呢?现在我来分析一波。
“==”的比较规则
首先我们去ECMAScript5.1中文版(http://lzw.me/pages/ecmascrip.)找一下“==”的比较规则,如下:
1.如果类型(x)与类型(y)相同,则为a。如果类型(x)未定义,则返回true。如果类型(x)为空,返回真。c .如果Type(x)是Number,I .如果x是NaN,则返回false。Ii .如果y是NaN,则返回false。Iii .如果x和y相等,返回true。四.如果x为0,y为0,则返回true。v .如果x为0,y为0,返回true。Vi返回false。如果类型(x)是字符串,当x和y是完全相同的字符序列(长度相等,相同的字符在相同的位置)时返回真。否则,返回false。如果类型(x)是布尔型,当x和y都为真或假时返回真。否则,返回false。f .当x和y引用同一个对象时返回true。否则,返回false。2.如果x为空,y未定义,则返回true。3.如果x未定义,y为空,则返回true。4.如果类型(x)是数字,类型(y)是字符串,则返回比较结果x==ToNumber(y)。5.如果类型(x)是字符串,类型(y)是数字,则返回数字(x)=y的比较结果。6.如果类型(x)是布尔值,则返回与数字(x)=y . 7的比较结果。如果Type(y)是布尔值,则返回比较x==ToNumber(y)的结果。8.如果类型(x)是字符串或数字,类型(y)是对象,则返回比较结果x==ToPrimitive(y)。9.如果类型(x)是对象,类型(y)是字符串或数字,则返回与主要类型(x)=y的比较结果。10.返回false
看了ECMAScript5.1中文版的介绍,相信很多朋友的心情应该是这样的:
别看上面说的。其实我们可以用很简单的话来概括。由于本文的核心是如何转换“==”,所以我将总结如何比较不同类型下的“==”。
当数据类型为布尔值或字符串时,比较时需要将其转换为数字。当数据类型是引用类型时,需要转换为原始数据类型。当转换后的原始数据类型为布尔值或字符串时,继续转换为数字。Undefined、null和任何值在“==”下返回false,但在“==”下都返回true。具体流程图如下:
备注:
Javascript的数据类型可以分为以下两种类型:
原始数据类型(空、未定义、数字、字符串、布尔值、符号(仅由es6引入))指对象(布尔值)和字符串到数字
布尔类型
布尔数字真1假0
字符串类型
如果标准数字格式是标准数字格式,那就不用说转换成数字类型了,比如下面的栗子:
123 '=123 ' 12.34 '=12.34 ' 0.12 '=0.12 '-12.34 '=-12.34非标准数字格式
但是,如果它是非标准数据格式,则应考虑两种情况:
第一种类型:只包含数字,最多有一个点。第二类:包含非数字且包含多个1分。仅包含数字,最多1个点
在这种情况下,将首先执行填充0和移除0的操作。下面我们来看看一些栗子:
01234'=1234' .1'=0.1' 12.=12' 1.000'=1'-02.30'=-2.3包含非数字并包含多个1点
在这种情况下,都返回NaN,意思是“不是数字”。这里要注意的是,NaN还是一个Number类型。这里有一些栗子:
123aa4 '=NaN ' hello,DD '=NaNtypeof NaN=' numer '将引用类型转换为原始数据类型的规则(ToPrimitive)
在介绍转换规则之前,我们首先介绍引用类型具有的两种方法:
对象。原型。tostringobject。原型。valueof可以将引用类型转换为原始数据类型。接下来,我们将详细介绍它们:
Object.prototype.toString
MDN解释如下:
tostring()方法返回一个表示对象的字符串。(tostring()方法返回表示此对象的字符串)
举个栗子:
const obj={ } console . log(String(obj))/'[Object Object]' obj . tostring=function(){ return '你好,仓老师!'}console.log(String(obj)) //“仓老师你好!”对象.原型.值Of
MDN解释如下:
方法的值返回指定对象的基元值。(方法的值返回该对象的原始数据值)
举个栗子:
const obj={ } console . log(Number(obj))//nanobj . value of=function(){ return 12345;} console . log(number(obj))//12345的值和toString的优先级
至于两者的优先级,在不同的情况下有不同的优先级。让我们根据不同的情况来介绍一下。
电话号码
看到一个栗子:
const obj={ toString(){ console . log('称为toString ');回报“仓老师你好!”;},valueOf(){ console.log ('valueOf调用');返回12345;} } console . log(Number(obj));控制台的输出结果:调用值12345。通过上述代码的运行结果,我们得出这样一个结论:
在ToNumber的情况下,valueOf的优先级高于toString。
接下来,让我们看看valueOf不返回原始数据类型的情况。
const obj={ toString(){ console . log('称为toString ');返回12345;},valueOf(){ console.log ('valueOf调用');返回{ };} } console . log(Number(obj));控制台的输出结果:调用的是valueOf,调用的是toString12345。从上面的运行结果,我们可以得出这样一个结论:
在ToNumber的情况下,如果valueOf返回的不是原始数据类型,则会自动调用toString。
打破砂锅到底,然后来到一个非常极端的情况,如果valueOf和toString都返回的不是原来的数据类型,那么应该会怎么样呢?同样,让我们继续看看运行结果:
const obj={ toString(){ console . log('称为toString ');返回{ };},valueOf(){ console.log ('valueOf调用');返回{ };} } console . log(Number(obj));控制台的输出结果:调用的valueOf调用的tostring unsughttypeerror :无法从上面的运行结果将对象转换为基元值,我们可以再次得出这样的结论:
在ToNumber的情况下,如果valueOf和toString都不返回原始数据类型,js将引发异常,指示引用类型无法转换为原始数据类型。
根据三组代码的运行结果,我们最后总结如下:
在ToNumber的情况下,js将首先调用valueOf。如果valueOf不返回原始数据类型,那么它将调用toString。如果toString不返回原始数据类型,js将引发异常,指示引用类型无法转换为原始数据类型。
具体流程图如下:
转换为字符串
看到一个栗子:
const obj={ toString(){ console . log('称为toString ');回报“仓老师你好!”;},valueOf(){ console.log ('valueOf调用');返回12345;} } console . log(String(obj));控制台输出结果:toStringHello,仓老师!通过以上代码的运行结果,我们得出这样一个结论:
如果是toString,ToString的优先级大于valueOf。
我们还来看看当toString返回的值不是原始数据类型时会发生什么:
const obj={ toString(){ console . log('称为toString ');返回{ };},valueOf(){ console.log ('valueOf调用');回报“仓老师你好!”;} } console . log(String(obj));控制台输出结果:调用toString,valueofhello,调用teachercan!根据运行结果,我们可以得到:
在toString的情况下,如果ToString不返回原始数据类型,将自动调用valueOf。
最后,让我们看看极端的情况,它们都不返回原始数据类型:
const obj={ toString(){ console . log('称为toString ');返回{ };},valueOf(){ console.log ('valueOf调用');返回{ };} } console . log(String(obj));控制台输出结果:调用了toString,调用了unsughttypeerror :的值无法将对象转换为基元值,我们发现:
在toString的情况下,如果ToString和valueOf都不返回原始数据类型,js将引发异常,指示引用类型无法转换为原始数据类型。
让我们综合三个结论:
在toString的情况下,js会先调用ToString。如果toString不返回原始数据类型,那么它将调用valueOf。如果valueOf不返回原始数据类型,js将引发异常,指示引用类型无法转换为原始数据类型。
具体流程图如下:
“==”下的值of和toString的优先级
根据上一篇文章总结的“==”的比较过程,引用类型转换为原始数据类型后,如果是Sting类型,会再次转换为Number类型。因此“==”下的引用类型在转换原始数据类型的过程中遵循ToNumber的优先级规则。
const obj={ toString(){ console . log('称为toString ');回报“仓老师你好!”;},valueOf(){ console.log ('valueOf调用');返回12345;} } console . log(obj==12345);控制台的输出结果:valueoftruenstoj={ ToString(){ console . log(' ToString called ')被调用;返回12345;},valueOf(){ console.log ('valueOf调用');返回{ };} } console . log(obj==12345);控制台的输出结果:调用了ToStringRuleInstobj={ tostring(){ console . log(' ToString called ')的值;返回{ };},valueOf(){ console.log ('valueOf调用');返回{ };} } console . log(obj==12345);控制台的输出结果:调用了toString,并且调用了非unsughttypeerror :值的类型转换无法将对象转换为基元值"=="
"=="只涉及到ToPrimitive和ToNumber,我们还介绍了ToBoolean和ToString,它们都不涉及。
ToBoolean
对于ToBoolean,我们只需要记住少数特例转为假,其余都是真的。
布尔(')=假布尔(未定义)=假布尔(空)=假布尔(0)=假字符串
数字到字符串
在将Number转换为String之前,它将首先执行移除0和填充0的操作,然后将其转换为String类型。
字符串(1.234)='1.234 '字符串(NaN)='NaN '字符串(. 1234)='0.1234 '字符串(1.23400)='1.234 '布尔值到字符串
字符串(真)='真'字符串(假)='假'空且未定义为字符串
字符串(空)='空'字符串(未定义)='未定义'对字符串的引用类型
引用类型首先转换为主要数据类型,如果转换后的原始数据类型不是字符串类型,则转换为字符串类型。
const obj={ toString(){ console . log('称为toString ');返回真;}}console.log(String(obj))控制台输出:调用了toString“true”摘要
“==”下的类型转换应该考虑两种情况。第一,原始数据类型;第二,引用类型。原始数据类型中的字符串类型和布尔类型需要转换为Number类型后再进行比较,而引用类型需要转换为原始数据类型后才能进行后续转换。弄清楚整个过程后,我们就能理解“==”中涉及的如何转换为Number和ToPrimitive了。按照这个理解步骤,我们会对“==”隐藏的类型转换有一个清晰的认识。另外,“===”并没有涉及到ToString和ToBoolean的类型转换,我也在文章后面部分补充了一下,希望能给朋友们对类型转换有更全面的了解。最后附上“==”类型转换的完整流程图:
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。