隐式转换,这个是JavaScript,这个时候的一些java中的经验不但不会帮助自己,还有可能会错误的引导自己。
数据类型
JavaScript的变量可以分为三种方式,字面量形式,包装器方式,以及new创建变量(对象)
基本数据类型: 字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。
上面之前的文章中有但是还有三个包装类
包装类: String Number Boolean
-
通过这三个包装类可以将基本数据类型的数据转换为对象
例如:
String() 可以将基本数据类型字符串转换为String对象
Number() 可以将基本数据类型的数字转换为Number对象
Boolean() 可以将基本数据类型的布尔值转换为Boolean对象注意:方法和属性能添加给对象,不能添加给基本数据类型。
a=1; b=Number(1) c=new Number(1) typeof(a) #"number" typeof(b) # "number" typeof(c) #"object"
数据类型又分引用值类型和基本类型。这个存储的有点像是java中的意思,也是分队和栈两个不同的存储类型。
这个现在可能没什么感觉,但是在JavaScript闭包等内容中会发现其神奇的之处。
其他数据类型隐式转换布尔类型
为什么会有这种隐式转换呢,现象看一个使用情况
if(12){
console.log(12);
}
# 在控制台输出
12
通过上面可以看出,数字类型其被转换成布尔类型了,不然也不会在if语句中生效。
以下可以看对应的布尔类型
数据类型 | true | false |
---|---|---|
Boolean | true | false |
String | 任何非空的字符串转换为true | “” 这样的空字符串隐式转换false |
Object | 任何对象(非null)会转换true | null 会转换false |
Number | 任何非O的数字(包括负数小数等) | 0或者NaN |
null | 会转换为false | |
NaN | 会转换为false | |
undefined | 会转换为false |
隐式转换中之 !
冒号(!)在很多语言中都有这个操作符,其作用是将操作符后面的数据转换成布尔类型,然后取反。
!后面的数据,会转换成布尔类型,其遵循的是其他数据类型隐式转换布尔类型表中的对应关系。
a=0
if (!a){
console.log("输出")
}
# 第一步 将a现在转换为布尔类型的值
#第二步 !将a转换的布尔类型的值取反。
补充&&和||的神奇用法
先举例子:
a=1;
b=a;
if (!a){
b=6;
}
#可以简写为
a=1;
b=a;
b=!a||6;
上面可以看出||的一个作用,其可以看出了神奇事情,简单的来说
#|| (| 一个的话 运算符)
遇见假就不会向后走,遇到真就向后走。
#&& (& 一个的话就是位运算符,两个才是逻辑运算符)
遇见假就会向后走,遇见真就不会运行后面的。
(& 与 &&,|与||的详细区别详解,后面单独弄一篇。)
上面理解清楚的话,现在看一下代码
a=1;
34 && (function(){ a=45;})()
console.log(a)
#输出的的a
45
第一步: 34 遇见&& 就将其转换成布尔值
第二步:判断布尔值为true,所以运行&& 后面的的数据
第三步:(function(){...})() 会自动执行,所以其自动运行后将a的值进行重新赋值。修改了a的值
可以看出使用&&或者||可以修改很多东西。
(这个涉及到(function(){...})() 后面单独讲解,简单理解那就是可以自动运行这个function)
上面的例子,在很多js的页面中使用,设置在在逆向js中的时候,也是一种常见的方式,用来进行简单混淆。甚至还可以&&和||一起用。比如:
#a的值是什么
a =1 && null || 8 && function test(){} && !2
#得到的a的值为
false
#将上面的方法编程可自行运行
a =1 && null || 8 && (function test(){})() && !2
#得到a的值
undefined
补充:上面可以看出,在根据&&和|| 判断是否为真假然后运行后面,但是如果其最后最后赋值的时候,还是会得到其本身的值,比如带有自行运行的时候,因为没有return的数据,所以其本身是undefined,所以将其赋值给a.
隐式转换中之 ==
a=5
b="5"
console.log(a==b) #true
console.log(a===b)#false
前面说过,== 不像是===那样不但匹配其值是否相等还判断其是否类型一样。可见==比较a和b的时候既然返回的true,说明==也是涉及到了隐式转换。
先说规律吧,然后看下面的例子
与原始值使用==比较的时候
-
如果两边类型不一致,其中一个是数字类型或者布尔类型,则两个都会转型成number类型。如果其中一个是引用类型,那就先调用valuesOf()方法,如果能转换成数字就可以对比,如果不能转换成数字的话,就需要调用tostring()转换成字符串。然后转成的字符串再转换为数字进行对比
补充:valueOf() 返回指定对象的原始值。
简单的说一下上面的隐式转换:当比较数字和字符串时,字符串会转换成数字值。 JavaScript 尝试将数字字面量转换为数字类型的值。
其中转换的时候用的是Number(字符串)进行转换。(不要使用parseInt()因最后的结果会不同,看下面的图)
如果是布尔类型呢?
这可以看出:
当数字通过==比较一个布尔类型的时候:先将布尔类型转换为数字类型(false对应的是0 true 对应的是1)
- 如果两边类型不一致,没有数字类型或者布尔类型,而是字符串的话。如果其中一个是引用类型,那就先调用valuesOf()方法,如果能转换成数字就可以对比,如果不能转换成数字的话,就需要调用tostring()转换成字符串。
比如下面:
都是引用数据类型
- 其对比的是存储的地址,所以下面两个转换成字符串虽然相等,但是其本身指向的堆的地址不同,所以不相等。
然后如果是两个对象呢?
以及下面包装类的Number和String进行对比
补充null、NaN、undefined
console.log(NaN==NaN) //false
console.log(undefined==null) //true
console.log(null==null) //true
console.log(undefined==undefined) //true
null、NaN、undefined ,相互比较的时候也不会参与隐式转换。
开始考试:
#第一题
new String('abc')==true
第一步:true 转数字 new String('abc')==1
第二步:new String('abc').valueOf()是字符串,所以不用调用tostring方法 : 'abc'==1
第三步:abc通过number转换数字返回NaN NaN==1
第四步: NaN就不用再隐式转换了 结果: false
# 第二题
[]==![]
第一步:虽然数组[]是引用类型,但是后面的数组前面有个!那就强制转换布尔类型 []==!true
第二步:!取反 []=false;
第三步:布尔值转换数字 []=0
第四步:数组[]中, []的valueof得不到原始值,所以调用tostring: ''==0
第五步:空字符串转换成0,变成 0==0 所以返回值true
总结来说:
1: 有基本数字类型和布尔值,==前后都变数。遇见引用先调用valueOf(),如若没有调tostring()。字符遵循number变数字。
2:基本字符串对比引用数据,也是先调用valueOf(),如若没有调tostring()。
3:引用数据比较数据存储地址。
4:null、NaN、undefined ,相互比较的时候也不会参与隐式转换。
大于或小于符
这个数字比较大小,就不在陈述,遵守数学的规则。
字符串比较大小
如果其中一个是数据一个是字符串的话,会涉及隐式转换
因为a转换数字的时候会变成NaN,所以无论对比什么数字都是返回fasle。
如果两个字符串都是数字呢?
先看图片
可以看出字符串比较大小,不会转换数字,而是遍历元素,依次对比,只有一个不相等就会终止后面的对比
'23'>'4'
第一步:因为第一个'2' 通过charCodeAt方法 为50 4通过charCodeAt方法 为52
第二步: 对比50<52 所以 后面不会再继续对比,根据这个结果作为比较大小的结果
第三步:所以结果为false。
补充:charCodeAt方法会ascii码对照的数字。
这个时候有人就疑问了,既然对比数字,那么其对比干嘛写成字符串?其实这个涉及到要给方法sort方法。
可以看出,sort方法是将数字变成字符串,然后才进行比较的。
+号
加号,这个其实也会涉及到隐式转换,比如前面说过任何类型数据+字符串都会转成字符串。
-
如果是两个原始数字类型相加直接遵循数学公式即可。
-
任何类型加上字符串,都会变成字符串。
-
原始数字
"a"+1 "a1"
-
字符串+字符串自然就是连接在一起。
-
字符串+引用类型数据
这个时候就涉及到隐式转换了,引用类型先通过valueof方法得到其原始值,如果没有原始值就需要调用tostring方法,然后进行相加。
a=[1,3,5] a+"test" 第一步: 数组a的 valueof 得到不是原始值数据,所以调用tostring方法 第二步: tostring调用的方法返回的数"1,2,5" 第三步:所以最后结果为"1,2,5test""
如果是null,undefined,NaN的话直接转化成字符串。
-
-
如果是原始数据类型加上非原始数据类型(null,undefined,NaN,布尔值除外),那么就遵循转换字符串的规律,然后相加为一个字符串。
- 布尔值 true为1,false为0
- 数字+引用类型数据
- null,undefined,NaN+原始数据类型
减号加号除号(- * /)
这三个和上面的不同,这三个隐式转换为数字的,来看下面验证;
当然如果前后无法都是非数字格式的其遵守转换数字的规律。先indexOf然后再tostring。
补充
对象类型valueof返回的原始值:
对象 | 返回值 |
---|---|
Date | 返回1970年1月1日0:00开始的毫秒数 |
Array | 返回数组对象本身 |
Function | 返回函数本身 |
Number | 返回原始值数字 |
Object | 一般返回对象本身 |
Boolean | 返回布尔值 |
String | 原始值的字符串 |
undefined,null,NaN等没有valueof方法 |
对象类型tostring返回的原始值:
对象 | 返回值 |
---|---|
Array | 以逗号分隔的由每个元素组成的字符串 |
Data | 返回一个本地时间格式的字符串 |
Function | 返回函数本身结构的字符串 |
Number | 返回字符串类型的数值 |
Object | [object Object] |
Boolean | 返回字符串的 true或者false |
String | 字符串 |
undefined,null,NaN等没有tostring方法 |