类型转换 & 隐式提升
最新的ECMScript定义了7种数据类型
原始类型
Booolean Null Undefined Number String Symbol
对象
Object
参考文档
类型装换
1、显示类型装换
1.1、Number函数
数值: 数值转换后还是原来的值
字符串:如果可以转换为数值,则转换为响应的数值,否则得到NaN。空字符串转为0
布尔值: true转成1,false转成0.
undefined:转成NaN
null : 转成0
console.log(Number(123))//123
console.log(Number('123'))//123
console.log(Number(false))//0
console.log(Number(true))//1
console.log(Number(undefined))//NaN
console.log(Number(null))//0
对象类型转换:
先调用对象自身的valueOf
方法,如果该方法返回原始类型的值(数值、字符串和布尔值),则直接对该值使用Number
方法,不再进行后续步骤。
如果valueOf
方法返回复合类型的值,再调用对象自身的toString
方法,如果toString
方法返回原始类型的值,则对该值使用Number
方法,不再进行后续步骤。
如果toString
方法返回的是复合类型的值,则报错。
let a = {b:1}
console.log(a.valueOf())//{ b: 1 }
console.log(a.toString()) //[object Object]
console.log('a', Number(a)) //a NaN
补充说明:
每个对象都有一个toString()方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。
默认情况下,toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中type是对象的类型。
1.2、 String函数
原始类型转换:
数值:转为响应的字符串
字符串:转换后还是原来的值
布尔值:true转为“true” , false 转为 “false”
undefined: 转为“undefined”
null: 转为"null"
对象类型转换
先调用toString
,如果toString
方法返回的是原始类型的值,则对该值使用STring方法,不再进行以下步骤。
如果toString方法返回的是符合类型的值,再调用valueOf方法,如果valueOf方法返回的是原始类型的值,则对该值使用String方法,不再进行以下步骤。
如果valueOf方法返回的是符合类型的值,则报错。
对象 | 操作 |
---|---|
Array | 将 Array 的元素转换为字符串。结果字符串由逗号分隔,且连接起来。 |
Boolean | 如果 Boolean 值是 true,则返回 “true”。否则,返回 “false”。 |
Date | 返回日期的文字表示法。 |
Error | 返回一个包含相关错误信息的字符串。 |
Function | 返回如下格式的字符串,其中 functionname 是被调用 toString 方法函数的名称:function functionname( ) { [native code] } |
Number | 返回数字的文字表示。 |
String | 返回 String 对象的值。 |
默认 | 返回 “[object objectname]”,其中 objectname 是对象类型的名称。 |
let b = {
b: 1
}
console.log(b.valueOf()) //{ b: 1 }
console.log(b.toString()) //[object Object]
console.log('b', String(b)) //b [object Object]
valueOf返回原始类型
let b = {
b: 1,
toString:function (params) {
console.log(123)
return {c:123};
},
valueOf:function (params) {
console.log(456)
return 'b'
}
}
控制台输出
{ c: 123 }
123
456
b b
valueOf返回对象,报错
let b = {
b: 1,
toString:function (params) {
console.log(123)
return {c:123};
},
valueOf:function (params) {
console.log(456)
return {d:123}
}
}
控制台输出:
{ c: 123 }
123
456
e:\icework\test\a.js:45
console.log('b', String(b)) //b [object Object]
^
TypeError: Cannot convert object to primitive value
下表列出了对象的valueOf()的返回值:
对象 | 返回值 |
---|---|
Array | 数组的元素被转换为字符串,这些字符串由逗号分隔,连接在一起。其操作与 Array.toString 和 Array.join 方法相同。 |
Boolean | Boolean 值。 |
Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。 |
Function | 函数本身。 |
Number | 数字值。 |
Object | 对象本身。这是默认情况。 |
String | 字符串值。 |
1.3、Boolean函数
原始类型转换
undefined、null、-0、+0、NaN、’’,这些都会转为false。其他的都转为true.
console.log(Boolean(123)) //true
console.log(Boolean('123')) //true
console.log(Boolean(false)) //false
console.log(Boolean(true)) //true
console.log(Boolean(undefined)) //false
console.log(Boolean(null)) //false
2、隐式类型转换
四则运算:加减乘除
判断语句:三目运算符
Native调用:比如调用console.log、alert,会调用string方法
常见问题:
[] + []
[] + {}
{} + [] //不同浏览器解释不同
{} + {} //[object Object]
true + true //2
1 + {a:1}
关于运算符的那些隐式类型转换
这部分一直是让我琢磨不透的,但是他的确应该有迹可循。
3、 加法运算操作符 加号运算操作符在Javascript也用于字符串连接符,所以加号操作符的规则分两种情况:
如果两个操作值都是数值,其规则为:
(1)如果一个操作数为NaN,则结果为NaN
(2)如果是Infinity+Infinity,结果是Infinity
(3)如果是-Infinity+(-Infinity),结果是-Infinity
(4)如果是Infinity+(-Infinity),结果是NaN
(5)如果是+0+(+0),结果为+0
(6)如果是(-0)+(-0),结果为-0
(7)如果是(+0)+(-0),结果为+0
如果有一个操作值为字符串,则:
如果两个操作值都是字符串,则将它们拼接起来
如果只有一个操作值为字符串,则将另外操作值转换为字符串,然后拼接起来
如果一个操作数是对象、数值或者布尔值,则调用toString()方法取得字符串值,然后再应用前面的字符串规则。
对于undefined和null,分别调用String()显式转换为字符串。
可以看出,加法运算中,如果有一个操作值为字符串类型,则将另一个操作值转换为字符串,最后连接起来。
4、 乘除、减号运算符、取模运算符
这些操作符针对的是运算,所以他们具有共同性:如果操作值之一不是数值,则被隐式调用Number()函数进行转换。具体每一种运算的详细规则请参考ECMAScript中的定义。
5、 逻辑操作符(!、&&、||)
5.1、逻辑非(!)操作符首先通过Boolean()函数将它的操作值转换为布尔值,然后求反。
5.2、逻辑与(&&)操作符,如果一个操作值不是布尔值时,遵循以下规则进行转换:
(1)如果第一个操作数经Boolean()转换后为true,则返回第二个操作值,否则返回第一个值(不是Boolean()转换后的值)
(2)如果有一个操作值为null,返回null
(3)如果有一个操作值为NaN,返回NaN
(4)如果有一个操作值为undefined,返回undefined
5.3、逻辑或(||)操作符,如果一个操作值不是布尔值,遵循以下规则:
(1)如果第一个操作值经Boolean()转换后为false,则返回第二个操作值,否则返回第一个操作值(不是Boolean()转换后的值)
(2)对于undefined、null和NaN的处理规则与逻辑与(&&)相同
6、 关系操作符(<, >, <=, >=) 与上述操作符一样,关系操作符的操作值也可以是任意类型的,所以使用非数值类型参与比较时也需要系统进行隐式类型转换:
(1)如果两个操作值都是数值,则进行数值比较
(2)如果两个操作值都是字符串,则比较字符串对应的字符编码值
(3)如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较
(4)如果一个操作数是对象,则调用valueOf()方法(如果对象没有valueOf()方法则调用toString()方法),得到的结果按照前面的规则执行比较
(5)如果一个操作值是布尔值,则将其转换为数值,再进行比较
注:NaN是非常特殊的值,它不和任何类型的值相等,包括它自己,同时它与任何类型的值比较大小时都返回false。
7、 相等操作符(==) 相等操作符会对操作值进行隐式转换后进行比较:
(1)如果一个操作值为布尔值,则在比较之前先将其转换为数值
(2)如果一个操作值为字符串,另一个操作值为数值,则通过Number()函数将字符串转换为数值
(3)如果一个操作值是对象,另一个不是,则调用对象的valueOf()方法,得到的结果按照前面的规则进行比较
(4)null与undefined是相等的
(5)如果一个操作值为NaN,则相等比较返回false
(6)如果两个操作值都是对象,则比较它们是不是指向同一个对象
例题解析
原题:+new Array(017),请问输出是什么?
let a = new Array(017)
console.log(a);
a.valueOf = function () {
console.log("valueOf被调用了!");
return a;
};
/*a.toString = function () {
console.log("toString被调用了!");
}*/
console.log(+a);
console.log(a,a.toString());
console.log(Number(a.toString())
[ <15 empty items> ]
valueOf被调用了!
NaN
[ <15 empty items>, valueOf: [Function] ] ',,,,,,,,,,,,,,'
NaN