你不知道的javaScript【笔记】— js隐/显式转换
同学,来,先来一套迷之转换热热身
![]==[] // 你猜
false==[]
''==null
''==0
是不是看的一脸懵逼?看完下面转换背后的规则再回来试试。
显示与隐式
首先显示转换和隐式转换式相对来说的,你明白这里要转换,那就是显示。你不明白,它还是会转换,它就是隐式,最直接的显示转换Number(),String(),Boolean(),注意都没用new操作符,所以返回的不是对象,而是进行相关转换。
三种常用转换的实现
1) ToString
在规范的9.8节中定义了抽象操作ToString(注意不是那个toString哦),它负责处理非字符串到字符串的强制类型转换。
基本类型值的字符串化规则是:
null=> ‘null’、 undefined=> ‘undefined’、 true=> ‘true’、 false=> ‘false’
数字的字符串化遵循通用规则。
关键是这里! 对象转换成字符串 是由抽象操作ToPrimitive完成的,它会先调用对象的toString()(这里除非自己定义了toString,不然都是返回对象的内部属性[[class]],Array.toString()就是例子),如果返回值是基础类型,就使用这个值。如果不是,就再调用原对象的valueOf方法,如果返回值为基本类型,就使用它强制转换成字符串,如果返回仍然不是基本类型,就报typeError的错误。
注意toString/valueOf都是自身没有,上[[proto]]找的(继承)
代码走一波
var obj={};
obj.toString()// "[object Object]" 返回的是字符串,就用你了!
String(obj) // "[object Object]" 果然是这样。
obj.hasOwnProperty('toString') //false 自己没有。valueOf同理
obj.__proto__.hasOwnProperty('toString') //true 继承得来
试试自定义valueOf和toString?
obj.valueOf=function(){return '我来自valueOf';}
obj.toString=function(){return '我来自toString';}
String(obj) //先调用toString,返回 '我来自toString',转换成功。
改一下toString,让他返回非基本类型
obj.toString=function(){return {};}
String(obj) // '我来自valueOf'
//先调用toString,返回{},不是基本类型,调用valueOf试试,返回'我来自valueOf'
自己修改valueOf试试看是不是TypeError: Cannot convert object to primitive value
*****这里强调一下Array.toString()
Array是Object的子类,它自己重写了toString,结果类似与Array.join(',');
var arr=[null,undefined,0,1,true,'Nijat'];
arr.toString() // ",,0,1,true,Nijat"
arr.join(',') //",,0,1,true,Nijat"
arr.__proto__==Array.prototype //true
Array.prototype.toString==Object.prototype.toString //false
删除这个屏蔽属性试试
delete Array.prototype.toString
Array.prototype.toString==Object.prototype.toString //true
arr.toString() //"[object Array]" // 哈 是[[class]]
2)ToNumber
负责将非数字转换成数字,基本类型转换为
true---->1
false---->0
undefined---->NaN
null---->0 //为什么是0呢?因为它的内存地址里全是0 也是typeof null=='object'的原因
string---->内容是数值类型就转成数字,不然就是NaN(Not a Number) ''->0 记住这个!
object怎么转呢 ? 很简单,参考ToString,但是调用顺序不同,ToNumber是先调用valueOf() 如果返回基本类型,再用基本类型转换为数字的方法去转换,如果返回对象,就去调用toString(),是基本类型,就转,还不是,就报错typeError。自己写代码看看。
3)ToBoolean
只需要记住这些falsy value,只有他们的转换结果是false
false null undefined '' +0、-0 NaN
其他的,结果都是true,无论它看起来多奇怪,他都是true。比如这位
var a1=new Boolean(false) //返回的可是对象
Boolean(a1) //true 对象不是falsy value,所以。。。
OK,记住那三种转换规则,要开始用了~
直接看==比较时出现的隐式转换吧,这个看明白了,其他的都很简单。
1)数字和字符串比较,字符串转数字。注意NaN不等于NaN
2)其他类型和布尔类型之间的比较
这里有个大坑! 只要存在布尔值,就先把布尔值转数字,参考ToNumber()
var a = 666;
var b=true;
a==b;
// 是不是会想a是666,不是falsy value,所以他是true,true==true 完美!确实666,但不是这样转换的~~
首先,b是布尔类型,所以要先把它转成数字,true-->1,然后判断666==1 法克!结果是false。
3)null 和undefined
这里我总结的是这样:
null==undefined //true;
undefined==null //true;
null==null //true
undefined==undefined //true
除此之外的任何基本类型与null/undefined比较 结果都是false
''==null //false
0==null //false
...
4)对象和对象之间,不转换!不转换!不转换! 比较引用的地址。
5)对象和非对象之间
对对象使用ToPrimitive,参考ToString
同学,来,再做一遍试试
![]==[] //true
// 先看左边 !显示转换boolean,[]不是falsy value,所以是true,!true-->false,现在呢,看看比较中有布尔值怎么处理,没错,先转数字,false-->0,现在是 0==[],成了对象与非对象之间,右边先toPrimitive(),是Array类型,它的toString()被重写过,所以是'', 原比较被转成了这样 0=='',数字和字符串比较,字符串转数字,记住Number('')结果是0,最后的最后 0==0? 所以结果是 true。
false==[] //true
''==null //false 只有undefined和null==null是true,其余都是false
''==0 //true
书中的解释和我的理解,有问题请指出
补充一点:判断类型的方法,最简洁和好使的一个:
Object.prototype.toString.call(xxx);
绕过各种toPrimitive,直接去取它的内部属性[[class]]