两种转换形式:显式类型转换和隐式类型转换
三种转换结果:数字、布尔值、字符串
1. 显式类型转换
常见的显式类型转换有构造函数形式Number()、String()、Boolean(),和new一个实例不一样哦
const a = new Number('123'); // a === 123 is false
const b = Number('123'); // b === 123 is true
a instanceof Number; // is true
b instanceof Number; // is false
基本类型转数字
-
Number()
直接上规范:如果传入参数,调用底层函数ToNumber(),如果未传入参数,返回+0
而调用底层函数ToNumber()有如下结果
参数类型 结果 Undefined NaN Null +0 Boolean true返回1,false返回**+0** Number 就是输入的参数了 String 情况比较复杂 String的说明
- 如果字符串中只包含数字**(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1" 会变成 1,"123"会变成 123,而"011"会变成 11(注意:前导的零被忽略了)**;
- 如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样,也会忽略前导零);
- 如果字符串中包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值;
- 如果字符串是空的(不包含任何字符),则将其转换为0;
- 如果字符串中包含除上述格式之外的字符,则将其转换为NaN。
console.log(Number("123")) // 123 console.log(Number("-123")) // -123 console.log(Number("1.2")) // 1.2 console.log(Number("000123")) // 123 console.log(Number("-000123")) // -123 console.log(Number("0x11")) // 17 console.log(Number("")) // 0 console.log(Number(" ")) // 0 console.log(Number("123 123")) // NaN console.log(Number("foo")) // NaN console.log(Number("100a")) // NaN
-
parseInt()和parseFloat()
这两个是针对字符串转数字的情况,因为用Number()转字符串的时候,复杂又不合理
-
parseInt()针对整数
-
忽略前导空格,第一个不为空的字符如果不是数字/正负号,就返回NaN;
-
解析后续字符直到遇到不是数字的字符,后面的字符全部忽略,返回之前的数字
parseInt(' +3') //+3 parseInt('') //空字符串,NaN parseInt(' ') //NaN parseInt('*12') //NaN parseInt('123blue') //123 parseInt(2.25) //2,'.'不是数字,小数点后面都被忽略了 parseInt('0xf') //15,十六进制 parseInt('070') //70,八进制,但是ES5认为这是70
-
第二个参数可以指定进制
parseInt('070',8) //56
-
-
parseFloat(针对浮点数)
-
只解析十进制
-
忽略前导0和空格,第一个不为空的字符如果不是数字/正负号,就返回NaN;
-
解析后续字符,第一次遇到小数点有效,第二次就无效了,其他非数字字符第一次就无效,返回前面的数字
console.log(parseFloat(' +3')); //3 console.log(parseFloat(' -3')); //3 console.log(parseFloat('')); //NaN console.log(parseFloat(' ')); //NaN console.log(parseFloat('*12')); //NaN console.log(parseFloat('123blue')); //123 console.log(parseFloat(2.25)); //2.25 console.log(parseFloat('2.25.4')); //2.25 console.log(parseFloat('0xf')); //0,遇到十六进制都是0 console.log(parseFloat('070')); //70
-
-
基本类型转字符串
-
String()
还是上规范:如果传入参数就调用底层函数ToString(),否则返回空字符串
ToString()结果如下
参数类型 结果 Undefined "undefined" Null "null" Boolean true返回**“true”,false返回"false"** Number 情况比较复杂 String 没转换 Number的说明
- NaN,转换为"NaN"
- +0/-0,转换为"0"
- Infinity,转换为"Infinity"
- 会进制转换
console.log(String(NaN)); //"NaN" console.log(String(-0)); //"0" console.log(String(+0)); //"0" console.log(String(-Infinity)); //"-Infinity" console.log(String(Infinity)); //"Infinity" console.log(String(0xf)); //"15" console.log(String(070)); //"56"
-
toString()
Boolean、Number、String是基本包装类型,有toString方法
null和undefined没有toString方法,所以没法转换
转换规则和ToString是一样的
console.log((-0).toString()); //0 console.log((NaN).toString()); //'NaN' console.log((0xf).toString()); //'15' console.log((070).toString()); //'56' console.log((-Infinity).toString()); //'-Infinity'
基本数据类型转布尔值
-
Boolean()
情况就没有那么复杂了,有6种值会被转换为false,其余均为true
//以下都是false console.log(Boolean()); console.log(Boolean(false)); console.log(Boolean(undefined)); console.log(Boolean(null)); console.log(Boolean(NaN)); console.log(Boolean('')); console.log(Boolean(-0)); console.log(Boolean(+0)); console.log(Boolean(0)); console.log(Boolean(' ')); //true
对象转数字/字符串
-
ToPrimitive()
基本类型转数字的时候就介绍了底层函数ToNumber(),给出的表格其实缺少了参数为对象时的情况,现在这里补上
参数类型 结果 Object 1. primValue = ToPrimitive(input, Number) 2. 返回ToNumber(primValue). 另一个底层函数ToString(),对于参数为对象有类似的处理
参数类型 结果 Object 1. primValue = ToPrimitive(input, String) 2. 返回ToString(primValue). 这里引入了另一个底层函数ToPrimitive(input,preferredType)—把输入转换为初始值,这个函数调用结果如下
参数类型 结果 基本数据类型 本身 Object blablabla一大堆,咱也没看懂,下面介绍好理解的处理方式 Object情况的说明:
-
preferredType == Number
- 调用valueOf(),结果为初始值就返回,否则下一步
- 调用toString(),结果为初始值就返回,否则下一步
- 抛出错误
-
preferredType == String
- 调用toString(),结果为初始值就返回,否则下一步
- 调用valueOf(),结果为初始值就返回,否则下一步
- 抛出错误
-
-
toString()和valueOf()
-
toString()
上面介绍基本数据类型转字符串的时候,介绍了这个方法,那么对象用这个方法呢?
var a = [1,2,3] var b = {val:4} var c = function(x){ return x++ } var d = new Date() var e = /\d+/g console.log(a.toString()); //'1,2,3' console.log(b.toString()); //"[object object]" console.log(c.toString()); //'function(x){ return x++ }' console.log(d.toString()); //Thu Apr 09 2020 17:55:26 GMT+0800 (中国标准时间) console.log(e.toString()); ///\d+/g
-
valueOf()
无论是哪种数据类型,返回参数本身,类型也不会变化,唯一特殊的是Date对象
var date = new Date() console.log(date.valueOf()); //1586426466217,1970.1.1距今的毫秒数
另外包装类型Number、String、Boolean,也是Object类,用valueOf后类型转换为基本数据类型
var c = new Number(12) console.log(c instanceof Number); //true console.log(c instanceof Object); //true console.log(c.valueOf()); //12 console.log(typeof c.valueOf()); //Number
-
-
转数字Number()
根据上面的分析,我们可以得出对象转数字的过程了
- 有**valueOf()**方法,就用,结果为基本数据类型就返回,否则下一步
- 有**toString()**方法,就用,结果为基本数据类型就返回,否则报错
- 得到基本数据类型primValue后,调用ToNumber(primValue),下面就很熟悉了
console.log(Number([1,2,3])); //NaN console.log(Number([])); //0 console.log(Number([0])); //0 console.log(Number({val:4})); //NaN console.log(Number({})); //NaN console.log(Number(function(x){ return x++ })); //NaN console.log(Number(new Date())); console.log(Number(/\d+/g)); //NaN
试着分析[]和[1,2,3]的情况
[].valueOf() == [],不是基本数据类型 [].toString() == '',是基本数据类型 ToString('') == 0
[1,2,3].valueOf() == [1,2,3],不是基本数据类型 [1,2,3].toString() == '1,2,3',是基本数据类型 ToString('1,2,3') == NaN
-
转字符串
参考转数字的过程,有
- 有**toString()**方法,就用,结果为基本数据类型就返回,否则下一步
- 有**valueOf()**方法,就用,结果为基本数据类型就返回,否则报错
- 得到基本数据类型primValue后,调用ToString(primValue),下面就很熟悉了
console.log(String([1,2,3])); //'1,2,3' console.log(String([])); //一个空格 console.log(String([0])); //'0' console.log(String({val:4})); //'[object Object]' console.log(String({})); //'[object Object]' console.log(String(function(x){ return x++ })); //'function(x){ return x++ }' console.log(String(new Date())); //'Thu Apr 09 2020 19:23:31 GMT+0800 (中国标准时间)' console.log(String(/\d+/g)); //'/\d+/g'
对象转布尔值
都转为true!包装类型也是!
2.隐式类型转换
最常见的就是运算符+、==或者if语句中的条件判断,其实还有比较运算符、自增++、自减–等等
一元运算符+a
调用ToNumber(),对+后面的数据进行转换,那么这个就很熟悉了
//基本数据类型
console.log(+'12.3'); //12.3
console.log(+'-12.3'); //-12.3
console.log(+''); //0
console.log(+true); //1
console.log(+null); //+0
console.log(+undefined); //NaN
//对象
console.log(+[]); //0
console.log(+[ ]); //0
console.log(+[1]); //1
console.log(+[1,2]); //NaN
console.log(+{}); //NaN
console.log(+{val: 'happy'}); //NaN
console.log(+new Date()); //1586433193168,1970.1.1距今毫秒数
二元运算符a+b
看规范吧🤯
-
left = ToPrimitive(a),right = ToPrimitive(b),a和b是基本数据类型的话,left = a,right = b
-
如果上述两个值有一个是字符串,ToString(left)拼接ToString(right)
-
否则ToNumber(left)加上ToNumber(right)
两个数字相加遵循以下规则
- 如果有一个操作数是 NaN,则结果是 NaN;
- Infinity + Infinity = Infinity;
- (-Infinity) + (-Infinity )= -Infinity;
- Infinity + (-Infinity) = NaN;
- (+0) + (+0) = +0;
- (-0) +(-0) = -0;
- (+0) + (-0) = +0。
console.log('1'+123); //'1123'
console.log(null+1); //1,两个都不是字符串,所以null转换为0,和1相加
console.log([]+[]); //'',经过ToPrimitive得到''+'' = ''
console.log(['1']+1); //'11',经过ToPrimitive得到'1'+1 = '11'
console.log([]+{}); //'[object Object]',经过ToPrimitive得到''+'[object Object]'
比较运算符a==b和a!=b
还是规范🤯,看吐了,11.9.3,这里给出精简版的
- 有一个为 NaN,则返回 false;
- a∈{null,undefined}且b∈{null,undefined},返回true,有一个不属于{null,undefined},返回false
- 如果a和b类型不一致
- a和b为 String、Number、Boolean 中的某一类型,则使用 ToNumber 函数转化为 Number 类型再进行比较;
- 有一个是Object,另一个是 String、Number、Boolean 中的某一类型,则ToPrimitive(Object)转换为基础数据类型,再按照上一步比较
- 相同类型,就好比较了
//规则1,全部是false
console.log(NaN == NaN);
console.log(null == NaN);
console.log(undefined == NaN);
//规则2
console.log(null == null); //true
console.log(undefined == undefined); //true
console.log(null == {}); //false
//规则3.1
console.log(1 == true); //true
console.log('1' == true); //true
console.log(0 == false); //true
console.log('1' == 1); //true
//规则3.2
console.log({} == {});
console.log([] == false); //true
console.log([0] == 0); //true
console.log(['0'] == 0); //true
//规则4
console.log([0] == ['0']); //false,这个脑子瓦特了,肯定false
console.log(+0 == 0); //true
console.log(-0 == 0); //true
console.log(+0 == -0); //true