摘要:抽象相等和严格相等。首先,也是如果有对象的话,会把对象转为基本类型值,在进行比较。
这一节,应该算是强制类型转换的最后一个小节了,这一部分呢,主要会讲比较操作中遇到的强制类型转换。
抽象相等(==)和严格相等(===)。
简单且粗略的来说,抽象相等和严格相等的区别就是抽象相等在比较的时候,如果比较的两个数类型不同,会先进行类型转换再比较,而严格类型呢,比较简单粗暴一些,直接返回false。
当然啦,你也可以这么理解,抽象比较的时候,允许类型转换,而严格相等则不允许,所以看如下例子:
console.log("1111" == 1111) // true console.log("1111" === 1111) // false
这个例子很容易理解,那么本例中,抽象相等中究竟是从字符串转换为数字呢,还是相反?
规范是这么说的:
如果相比较的两个操作数,其中一个是数字类型,另一个是字符串类型的话,那么字符串将会转换为数字,再进行比较,就相等于:
console.log(Number("1111") == 1111);
那么如果是布尔值呢?比如说
console.log("42" == true); // false console.log(12 == true); // false console.log(-1 == true); // false
哇哦,都是false呀,是不是和一开始的认知不太一样呢?尤其是对于有其他语言基础的童鞋们。
这一方面ecma规范也有说了:
如果操作数中,有布尔类型的,那么他将会转为数字类型,再进行比较。
大家请看着个例子,应该不用多说了吧,上面说过了,严格相等的话,如果类型不一样,直接返回false,毕竟人家是严格相等,很严格的。
console.log(false === 0); // false console.log(false == 0); // true
那么如果null和undefined比较呢?
console.log(null == null); // true console.log(undefined == null); // true console.log(undefined == undefined) // true
第一个和第三个大家比较容易理解,第二个可能比较疑惑,为甚呢?
因为规范上有说,如果比较的两种,一个是undefined另一种是null,则返回true,但是这个也只是对应于抽象相等,严格相等时不可能相等的。因为类型不一样。
至于上面那个呢,我还应该多说一句,除了undefined和null比较或者是他们同类型的比较是true,和其他任何类型的值比较都是false,有一些看起来像true的,结果都是false,要注意一下。
console.log(null == false); // false console.log(undefined == 0); // false console.log(undefined == "") // false
接下来这个比较重要了,就是对象和非对象的比较。
先看规范定义吧:
对于两个操作数,如果其中一个是字符串或数字,另一个是对象的话,那么对象会转为原始值,然后再进行比较。
那么怎么获取原始值呢?
其实其他小节也都讲过,这里在复述一下,简单来说,就是先调用对象的valueOf()函数,如果它不存在,或者不会转为基本类型值,就调用toString()函数,如果toString()不存在或者返回的是非字符串的值,将会直接报错。
看起来有一点枯燥吧,那么看例子。
console.log([2].valueOf()); // [2] console.log([2].toString()); // "2" console.log([2].toString() == 2); // true
数组[2]呢,可以看到,他的valueOf返回的是一个数组,那么他就会用toString(),转为字符串“2”,字符串2和数字2比较呢,根据上面讲的,字符串2会变为数字2,相等,返回true。
在看一个例子
var obj = { valueOf() { return 3; } } console.log(obj == 3); // true var obj1 = Object.create(null); console.log(obj1 == 3); // Uncaught TypeError: Cannot convert object to primitive value
这个呢,就是对象先调用valueOf()得到基本类型值3,然后再进行比较得到true,第二个呢,得到了一个纯净的对象(没有prototype),然后获取不到valueOf()和toString(),直接报错了。
那其他的情况呢
console.log(NaN == NaN); // false console.log(NaN === NaN); // false console.log(+0 == -0); // true console.log(+0 === -0); // true console.log({} == {}); // false console.log({} === {}); // false var obj1 = obj = {}; console.log(obj == obj1); // true console.log(obj === obj1); // true
这个分析一下,规范中:
NaN不等于自身,+0和-0是相等的,对象是否相等是根据是否引用同一对象。
对象相等的已经介绍完了,那么判断不相等的呢?比如说(!=)和(!==)他们的区别呢
实际上,他们的语法判断规则和相等的规则一样,只不过最后多了一个置反的一个步骤。也就是!(a == b)或者是!(a === b),我感觉应该很容易理解,就不举例了。
那么最后就要讲关系操作符了,也就是大于小于这些的。
那么我们先讲两个操作符中,有至少是一个数字的情况。请看下面的例子
console.log(1 < 2); // true console.log("0b1" < 2); // true var obj = { valueOf() { return 1; } } console.log(obj < 2); // true console.log(1 < Infinity); // true console.log(-Infinity < 1); // true console.log(NaN > 1); // false console.log(NaN < 1); // false
上面这几个例子,几乎涵盖了规范中至少有一个操作数是数字的比较的情况。
首先,也是如果有对象的话,会把对象转为基本类型值,在进行比较。
并且如果另一个操作数是字符串的话,会把字符串转成数字。
还有就是数字一直小于正无穷,大于负无穷。
NaN无论怎么判断都是false。
那么如果是字符串之间的比较呢,也就是俩操作数都是字符串的情况。
console.log("1003" > "2"); // false
嗯,很简单是吧,如果俩都是字符串的话,实际上会按照字母顺序去比,这样去排出哪个值。
那么是怎么按照字母顺序比的呢,字母顺序又是通过什么方式取得的呢?请看例子:
console.log("aaa" > "aa"); // true console.log("1003" > "2"); // false console.log("a" > "b"); // false console.log("&" < "a"); // true console.log("A" < "a"); // true console.log("a".charCodeAt()); // 97 console.log("b".charCodeAt()); // 98 console.log("&".charCodeAt()); // 38 console.log("A".charCodeAt()); // 65
这个例子,应该就很容易理解了,实际上取的是字符串的charCodeAt(),实际上你依然可以理解为转换成数字去比了,只不过字符串的比和含有数字的比是不一样的,数字的比意味着他们整体数字的值的大小去比,而字符串是比从一开始的前缀挨个比每个字母的大小。
是不是依然比较好理解,那么在来一个例子。
var a = [ 42 ]; var b = "043"; console.log(a < b); // false console.log(Number(a) < Number(b)); // true
这个结合上面那个规则,自己分析下。
最后的最后,我们看一个你可能略感疑惑的例子:
var a = { b: 42 }; var b = { b: 43 }; console.log(a < b); // false console.log(a == b); // false console.log(a > b); // false console.log(a <= b); // true console.log(a >= b); // true
这个例子,确实不太付合常识呀,但是呢,这确实是存在的,我给解释一下。
首先呢,a < b和a > b,由于他们俩都是对象,所以转换为基本类型值后为字符串“[object Object]”,所以返回false,而a == b呢,则是因为他俩并不是同一个对象的不同的引用,所以返回false。
最后俩呢,实际上大于等于或者小于等于可以理解为大于或者小于的值的反值,也就是: !(a <= b),所以前面为false,反一下为true
好啦,三个小章基本把强制类型转换整个梳理了一遍,因为这一块的细节太多,所以说呢,我反倒是建议读到我这里的小伙伴,先把大体规则了解以后,特别细节的规则,用到的时候看看我的小散文,或者直接去看ecma262标准文档也行,但是呢,强调一点就是,假如真的要用之前,还是建议自己吧代码跑一下,这样我的感触就是要比只看效果好太多。
总之感谢大家收看我的小散文。
参考书籍《你不知道的Javascript中卷》
参考文档:ECMAScript 5.1(ECMA-262)
https://www.ecma-internationa...
本文转载自http://www.lht.ren/article/7/
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100726.html
摘要:所以无论还是都会进行类型转换,唯一的区别,就是会置否而不会。这时候,肯定会有人问,假如说我有其他的数据类型呢,又不是数字又不是字符串,比如说数组啊,对象啊,布尔值啥的,那么如果是引用数据类型,则先转为基本数据类型,再进行比较。 上一章主要讲了转换到数字,字符串和布尔类型的一些知识点,那么这一讲接着上面的继续讲。 思考下面这个问题: console.log(+123); // 123 ...
摘要:转换为字符串规则如下图代码大致就是普通其他基本类型转为字符串的话,就直接转为其值的字符串表达形式,如果是基本类型的封装对象,会先拆封,然后再转为字符串,如果是普通对象,则会调用其内部的值,如果是极大数和级小数,将会进行一些转化,具体规 转换为字符串规则如下图代码: console.log(String(undefined)); // undefined console.log(Str...
摘要:前缀规范每个局部变量都需要有一个类型前缀,按照类型可以分为表示字符串。例如,表示以上未涉及到的其他对象,例如,表示全局变量,例如,是一种区分大小写的语言。布尔值与字符串相加将布尔值强制转换为字符串。 基本概念 javascript是一门解释型的语言,浏览器充当解释器。js执行时,在同一个作用域内是先解释再执行。解释的时候会编译function和var这两个关键词定义的变量,编译完成后从...
摘要:一返回值调用外部方法获取的值需要对类型做判断,因为我们对方法返回的值是有期望值类型,但是却不能保证这个接口返回的值一直是同一个类型。 19年目标:消灭英语!我新开了一个公众号记录一个程序员学英语的历程 有提升英语诉求的小伙伴可以关注公众号:csenglish 程序员学英语,每天花10分钟交作业,跟我一起学英语吧 javascript作为一门动态类型语言,具有很高的动态灵活性,当定义函数...
摘要:实际上,我们通常认为是自有类型的唯一成员。比较运算符的操作数可能是任意类型。结果只有,例得到操作值等价的布尔值真值为,假值为等同于,经常称为强制转换。结果返回布尔值的用法是中唯一一个不等于任何值的包括它自己。 说起 js 类型转换,都是头疼吧,晕晕的,但是不行啊,这东西很重要滴! 基础知识 JavaScript的数据类型分为六种,分别为null, undefined, boolean,...
阅读 1007·2021-10-27 14:15
阅读 2763·2021-10-25 09:45
阅读 1921·2021-09-02 09:45
阅读 3357·2019-08-30 15:55
阅读 1798·2019-08-29 16:05
阅读 3189·2019-08-28 18:13
阅读 3108·2019-08-26 13:58
阅读 441·2019-08-26 12:01