一、显式类型转换
1. 原始值的转换
1.1 转布尔值 boolean
使用 Boolean() 函数:
Boolean() // false ,不传任何参数时,返回 false
Boolean(false) // false
// undefined => boolean
Boolean(undefined) // false
// null => boolean
Boolean(null) // false
// number => boolean
Boolean(+0) // false
Boolean(-0) // false
Boolean(NaN) // false , typeof NaN // number
// string => boolean
Boolean('') // false
1.2 转数字 number
/* 根据规范
* - Number() 函数不传参数,返回 0 ;
* - 有参数,调用底层方法 ToNumber(value): 无法被转换为数字的参数,返回 NaN;
*/
// undefined
ToNumber(undefined) // NaN
// null
ToNumber(null) // 0
// boolean
ToNumber(true) // 1
ToNumber(false) // 0
使用 Number() 函数:
Number() // 0
// undefined => number
Number(undefined) // NaN
// null => number
Number(null) // 0
// bollean => number
Number(false) // 0
Number(true) // 1
// string => number
// - 视图转换成一个整数或浮点数;
// - 忽略所有前导的 0;
// - 如果有一个字符不是数字,返回 NaN;
Number('123') // 123
Number('-123') // -123
Number('1.2') // 1.2
Number('000123') // 123
Number('-000123') // -123
Number('0x11') // 17
Number('') // 0
Number(' ') // 0
// 无法转为数字的参数,返回 NaN
Number('123 123') // NaN
Number('foo') // NaN
Number('100a') // NaN
1.3 转字符 string
/* 根据规范
* - String() 函数不传参数,返回空字符串;
* - 有参数,调用 ToString(value);
*/
// undefined
ToString(undefined) // undefined
// null
ToString(null) // null
// boolean
ToString(true) // true
ToString(false) // false
使用 String() 函数:
String() // ''
// undefined => string
String(undefined) // 'undefined'
// null => string
String(null) // 'null'
// boolean => string
String(false) // 'false'
String(true) // 'true'
// number => string
String(0) // '0'
String(-0) // '0'
String(NaN) // 'NaN'
String(Infinity) // 'Infinity' , typeof Infinity // 'number'
String(-Infinity) // '-Infinity'
String(1) // '1'
1.4 转对象 object
原始值调用 String()、Number() 、Boolean() 构造函数,转换为它们各自的包装对象:
null 和 undefined 属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误(TypeError)异常,而不会执行正常的转换;
typeof 1 // 'number'
typeof new Number(1) // 'object'
typeof new String(1) // 'object'
typeof new Boolean(1) // 'object'
2. 对象的转换
2.1 转布尔值 boolean
对象转布尔值很简单,使用 Boolean() 函数,所有对象都转换为 true ,包括数组和对象:
Boolean([]) // true
Boolean(new String(1)) // true
Boolean(new Number(1)) // true
Boolean(new Boolean(1)) // true
2.2 转数字 number 和字符 string
- 都是通过
调用待转换对象
的一个方法来完成的; - js对象有
toString() 、valueOf()
两个不同的方法; - 所有对象,除了
null 、undefined
之外的任何值都具有 toString() 方法,和 String() 方法返回的结果一致;
调用 toString() 方法
- 数组的 toString() 方法将每个数组元素转换成一个字符串,并在元素之间添加逗号后合并成结果字符串;
- 函数的 toString() 方法返回源代码字符串;
- 日期的 toString() 方法返回一个可读的日期和时间字符串;
- 正则的 toString() 方法返回一个正则表达式直接量的字符串;
// 一般对象
({}).toString() // '[object Object]'
// 数组
[].toString() // ''
[0].toString() // '0'
[1,2,3].toString() // '1,2,3'
// 函数
(function(){var a = 1}).toString() // 'function(){var a = 1}'
// 日期
(new Date(2022,4,1)).toString() // 'Sun May 01 2022 00:00:00 GMT+0800 (中国标准时间)'
// 正则
(/\d+/g).toString() // '/\\d+/g'
调用 valueOf() 方法
- 默认的 valueOf() 方法返回对象本身;
- 日期列外,返回它的一个内容:1970.1.1 以来的毫秒数;
new Date(2022,4,1).valueOf() // 1651334400000
调用 ToPrimitive() 方法
都要先调用 ToPrimitive(obj [,type])
方法:输入一个值,返回一个一定是基本类型的值;
- 第一个参数是 obj :表示要处理的输入值;
- 第二个参数是 type ,非必填,表示希望转换成的类型,Number 或 String;
- 当不传 type 时,如果 input 是日期类型,相当于传入了 String ,否则都相当于传入了 Number;
- 如果传入的 input 是 undefined、null、boolean、number、string 类型,直接返回该值;
如果是 ToPrimitive(obj,Number)
,即转换成数字 number,处理步骤如下:
- 如果 obj 是基本类型,直接返回;
- 否则,调用 valueOf() 方法,如果返回一个原始值,则 js 将其返回;
- 否则,调用 toString() 方法,如果返回一个原始值,则 js 将其返回;
- 否则,js 抛出类型错误异常;
如果是 ToPrimitive(obj,String)
,即转换成字符 string,处理步骤如下:
- 如果 obj 是基本类型,直接返回;
- 否则,调用 toString() 方法,如果返回一个原始值,则 js 将其返回;
- 否则,调用 valueOf() 方法,如果返回一个原始值,则 js 将其返回;
- 否则,js 抛出类型错误异常;
🌰
// 一般对象
Number({}) // NaN
Number({a:1}) // NaN
// 数组
// - Number([]):
// - ①对象转原始值:先调用 [].valueOf() ,返回 [];不是原始值,继续调用 [].toString() ,返回空字符串;
// - ②原始值转数字:js 底层调用 ToNumber(value)
Number([]) // 0
Number([0]) // 0
Number([1,2,3]) // NaN
Number(function(){var a = 1}) // NaN
Number(/\d+/g) // NaN
Number(new Date(2022,4,1)) // 1651334400000
Number(new Error('a')) // NaN
3. JSON.stringify
JSON.stringify() 可以将一个 js 值转换为一个 JSON 字符串:调用 toString() 方法;
1. 基本类型
结果与使用 String()(底层调用 toString())基本相同,结果都是字符串,除了 undefined;
JSON.stringify(null) // 'null'
JSON.stringify(undefined) // undefined ,非字符串
JSON.stringify(true) // 'true'
JSON.stringify(18) // '18'
JSON.stringify("18") // '"18"'
JSON.stringify('18') // '"18"'
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(18) // '18'
String("18") // '18'
String('18') // '18'
2. Boolean、Number、String 的构造函数
在序列化过程中会自动转换成对应的原始值:
JSON.stringify([new Boolean(1), new Number(2), new String(3)]) // '[true,2,"3"]'
3. undefined、Symbol、任意函数
在序列化过程中:
- 会转换成 null (出现在数组对象中);
- 会被忽略(出现在非数组对象的属性值中时);
// 数组对象中:null
JSON.stringify([undefined, Object, Symbol("")]) // '[null,null,null]'
// 非数组对象中:忽略
JSON.stringify({a: undefined, b: Object, c: Symbol("")}) // '{}'
二、隐式类型转换
js 自动将数据类型进行了转换;
1. 操作符 +
1.1 一元操作符 +
当 + 运算符作为一元操作符的时候,会调用 ToNumber() 处理该值;
+'1' // 1
/* 对象转数字:
* - ①对象转原始值:先调用 valueOf() ,如果返回不是原始值,继续调用 toString();
* - ②原始值转数字:js 底层调用 ToNumber(value)
*/
+[] // 0
+['1'] // 1
+['1','2','3'] // NaN
+{} // NaN
1.2 二元操作符 +
当 + 运算符作为二元操作符时(例:a+b) :
- ① 如果 a、b 存在对象,先调用 ToPrimitive(value) 转为原始值;
- ② 如果 a、b 存在字符串,返回字符串 a 和字符串 b 的拼接结果;
- ③ 返回 ToNumber(a) 和 ToNumber(b) 的运算结果;
1. null 和数字
null+1 // 1
// 解析:
// - ① 都是基本类型,调用 ToPrimitive(null|1, Number) ,都是直接返回 null 、1;
// - ③ 不需要拼接字符串,最终结果为:null + 1 = ToNumber(null) + ToNumber(1) = 0 + 1 = 1 ;
2. 数组和数组
[]+[] // ''
// 解析:
[].valueOf() // []
[].toString() // ''
// - ① 都是数组对象,调用 ToPrimitive([], Number) 转换成原始值 :
// - 先调用 valueOf() ,均返回对象本身 [];
// - 非原始值,再调用 toString() ,均返回空字符串;
// - ② 都是字符串,拼接字符串,即最终结果为:[] + [] =''+'' = '';
3. 数组与对象
([]+{}) // '[object Object]'
({}+[]) // '[object Object]'
// 解析:
[].valueOf().toString() // ''
({}.valueOf()) // {}
({}.valueOf()).toString() // '[object Object]'
// - ① 都是对象,调用 ToPrimitive([]|{}, Number) 转换成原始值:
// - 先调用 valueOf() ,返回对象本身: [] 、{} ;
// - 非原始值,再调用 toString() ,均返回字符串:''、'[object Object]';
// - ② 都是字符串,拼接字符串,即最终结果为:[] + {} ='' + '[object Object]' = '[object Object]' ;
更多🌰
// 举例一
1+true // 2
Number(true) // 1
Number(1) // 1
// 举例二
{}+{} // '[object Object][object Object]'
({}.valueOf()).toString() // '[object Object]'
// 举例三
new Date(2022,4,1)+1 // 'Sun May 01 2022 00:00:00 GMT+0800 (中国标准时间)1'
// 解析:
new Date(2022,4,1).toString() // 'Sun May 01 2022 00:00:00 GMT+0800 (中国标准时间)'
// - ① 存在 date 对象,调用 ToPrimitive(value, String) 转换成原始值:
// - 先调用 toString() , 返回原始值字符串 ;
// - ② 存在字符串,拼接字符串,即最终结果为:'Sun May 01 2022 00:00:00 GMT+0800 (中国标准时间)' + 1 = 'Sun May 01 2022 00:00:00 GMT+0800 (中国标准时间)1' ;
2. 操作符 ==
'=='用于比较两个值是否相等,当要比较的两个值类型不一样的时候,就会发生类型转换(例如:x==y);
1. null 和 undefined
- x 是 null,y 是 undefined,返回 true;
- x 是 undefined,y 是 null,返回 true;
null==undefined // true
2. 字符串和数字
均转换成数字
进行比较:
- x 是数字,y 是字符串,返回 x == ToNumber(y);
- x 是字符串,y 是数字,返回 ToNumber(x) == y;
1=='1' // true
'1'==1 // true
3. 布尔值和其他类型
- x 是布尔值,返回 ToNumber(x) == y;
- y 是布尔值,返回 x == ToNumber(y);
true=='1' // true
true=='2' // false
true=='3' // false
// 解析
Number(true) // 1
Number('1') // 1
4. 对象与非对象
- x 是数字或非字符串,y 是对象,返回 x == ToPromitive(y);
- x 是对象,y 是数字或非字符串,返回 ToPromitive(x) == y;
18==['18'] // true
// 解析
['18'].valueOf() // ['18']
['18'].valueOf().toString() // '18'
5. 其他
console.log( false == undefined ) // false
console.log(false == []) // true
console.log([] == ![]) // true
console.log(false == "0") // true
console.log(false == 0) // true
console.log(false == "") // true
console.log("" == 0) // true
console.log("" == []) // true
console.log([] == 0) // true
console.log("" == [null]) // true
console.log(0 == "\n") // true
console.log([] == 0) // true