为了转生而点技能-JavaScript,难题纪录(二)隐式转换规则及===、==

隐式转换规则

前言:

涉及隐式转换最多的两个运算子 + 和 ==。
+运算子即可数字相加,也可以字串相加。
== 不同于===,故也存在隐式转换。
减、乘、除这类运算子只会针对number型别,故转换的结果就是转换成number型别。


转换表

http://img2.58codes.com/2024/20143762yUTVcyol3N.png


规则:

第一步:决定该转换成什么类型:

加号(+)专属规则:

当一侧为String类型,加号(+)会被定义为字元串接,并会让另一侧优先转换为字串。当一侧为Number类型,另一侧为原始类型(primiary type),原始类型会转换为Number型。当一侧为Number类型,另一侧为引用类型(reference type:Array , Function , Object ),引用类型(一侧)和Number型(另一侧)皆转换成字串后串接。

优先顺序为由上而下!

第二步:需转换侧的值该如何转。

将值转为原始值,ToPrimitive():
js引擎内部的抽象操作ToPrimitive有着这样的签名:ToPrimitive(input, PreferredType?)
input是要转换的值,PreferredType是可选引数,可以是Number或String型别,由第一步决定。

2-1. PreferredType是Number型(第一步决定该转换为Number型)时:

如果输入的值已经是一个原始值,则直接返回它否则,如果输入的值是一个物件,则呼叫该物件的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。否则,呼叫这个物件的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。否则,丢掷TypeError异常。

2-2. PreferredType是String型(第一步决定该转换为String型)时:

如果输入的值已经是一个原始值,则直接返回它否则,呼叫这个物件的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。否则,如果输入的值是一个物件,则呼叫该物件的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。否则,丢掷TypeError异常。

2-3. PreferredType在第一步没有办法指定转换哪一种型时:

该物件为Date型别,则PreferredType被设定为String,并重複2-1的流程。补充:(前端工程研究:关于 JavaScript 中 Date 型别的常见地雷与建议作法)否则,PreferredType被设定为Number,并重複2-2的流程。

3-1.valueOf()方法:

Number、Boolean、String这三种建构函式生成的基础值的物件形式,通过valueOf转换后会变成相应的原始值。Date这种特殊的物件,其原型Date.prototype上内建的valueOf函式将日期转换为日期的毫秒的形式的数值。除此之外返回的都为this,即物件本身。
var num = new Number('123');num.valueOf(); // 123var str = new String('12df');str.valueOf(); // '12df'var bool = new Boolean('fd');bool.valueOf(); // truevar a = new Date();a.valueOf(); // 1515143895500var a = new Array();a.valueOf() === a; // truevar b = new Object({});b.valueOf() === b; // true

3-2.toString:

Number、Boolean、String、Array、Date、RegExp、Function这几种建构函式生成的物件,通过toString转换后会变成相应的字串的形式。其他物件返回的都是该物件的型别。参考转换表。

第三步:原始值转换。

经过前面步骤,会得到一个原始值,之后依照运算子的需求选择利用ToNumber将该原始值转换成数自型态;或是利用ToString将该原始值转换为字串,转换规则参考顶层的转换表。


试解:

第一题:

({} + {}) = ?
两个物件的值进行+运算子,肯定要先进行隐式转换为原始型别才能进行计算。

第一步:决定该转换成什么类型:因为不属于+号的3个条件,属于2-3.之情况。
1、第二步:ToPrimitive转换,由于没有指定PreferredType型别,{}会使预设值为Number,进行ToPrimitive(input, Number)运算。
2、所以会执行valueOf方法,({}).valueOf(),返回的还是{}物件,不是原始值。
3、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
故得到最终的结果,"[object Object]" + "[object Object]" = "[object Object][object Object]"

第二题:

2 * {} = ?
1、首先乘号运算子只能对number型别进行运算,故第一步就是对{}进行ToNumber型别转换。
2、由于{}是物件型别,故先进行原始型别转换,ToPrimitive(input, Number)运算。
3、所以会执行valueOf方法,({}).valueOf(),返回的还是{}物件,不是原始值。
4、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
5、转换为原始值后再进行ToNumber运算,"[object Object]"就转换为NaN。
故最终的结果为 2 * NaN = NaN



严格相等(===)

定义:比较两侧的值是否在型态上及数值上皆相同。

NaN === NaN;  //false+0 === -0;    //true

宽鬆相等(==)

定义:宽鬆相等不限于型态相同,即型态不相同也可宽鬆相等。

1 == '1' // true

运作方式:

一侧为boolean值的宽鬆相等比较:
值首先会被转换为数字类型,根据boolean类型的ToNumber规则,true转为1,false转为0。数字类型和字串类型的宽鬆相等比较:
当数字类型和字串类型做宽鬆相等比较时,字串类型会被转换为数字类型;根据字串的ToNumber规则,如果是纯数字形式的字符串,则转为对应的数字,空字符转为0, 否则一律按转换失败处理,转为NaN。
注意NaN不与任何值相等,包括它自己。
注意字串内如果是16进位制,也算纯数字。当引用型别和原始型别的宽鬆相等比较:
对象类型会依照ToPrimitive规则转换为原始类型

试解:

第一题:

[2] == 2 // true

解:

属于引用型别和原始型别的宽鬆相等比较。[2]做ToPrimitive操作,因为[2]非data型(2-3.),所以PreferredType是Number型[2]也就是先调用valueOf,回传仍是[2]。[2]再调用toString,回传是'2'。'2'已经符合数字类型和字串类型的宽鬆相等比较之条件,ToNumber变成2。

第二题:

[] == !{} // true

1、! 运算子优先顺序高于==,故先进行!运算。
2、!{}运算结果为false,结果变成 [] == false比较。
3、属于一侧为boolean值的宽鬆相等比较:
等式右边y = ToNumber(false) = 0。结果变成 [] == 0。
4、属于当引用型别和原始型别的宽鬆相等比较:
[]会先呼叫valueOf函式,返回this。
不是原始值,继续呼叫toString方法,x = [].toString() = ''。
故结果为 '' == 0。
5、属于数字类型和字串类型的宽鬆相等比较:
等式左边x = ToNumber('') = 0。
所以结果变为: 0 == 0,返回true,比较结束。



参考文章:

IT人-javascript 隐式转换:https://iter01.com/472967.html程式前沿-从一道面试题说起—js隐式转换踩坑合集:https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/701003/#outline__1JavaScript 隐式类型转换,一篇就够了!:https://chinese.freecodecamp.org/news/javascript-implicit-type-conversion/

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章