类型转换
一、规则
二、分类
-
隐式类型转换: 在执行过程中当js内部期望得到某种类型的值,而实际在那里的值是其他的类型,就会发生隐式类型转换。系统内部会自动调用我们前面说
ToBoolean ( argument )
、ToNumber ( argument )
、ToString ( argument )
,尝试转换成期望的数据类型。 -
显示类型转换: 手动调用
Boolean(value)
、Number(value)
、String(value)
完成的类型转换。
三、原理
-
ToPrimitive ( input [ , PreferredType ] ):
ToPrimitive
将input
装换为基本数据类型,PreferredType
要么不传,要么是number
、string
。-
PreferredType
为number
:-
如果
input
本身就是原始类型,直接返回input
。 -
调用
input.valueOf()
,如果结果是原始类型,则返回这个结果。-
number.valueOf()
:console.log((1).valueOf(), typeof (1).valueOf()); // 1 number
-
string.valueOf()
:console.log("1".valueOf(), typeof "1".valueOf()); // 1 string
-
boolean.valueOf()
:console.log((true).valueOf(), typeof (true).valueOf()); // true boolean
-
object.valueOf()
:console.log({}.valueOf(), typeof {}.valueOf()); // {} object
console.log({ a: 1 }.valueOf(), typeof { a: 1 }.valueOf()); // { a: 1 } object -
array.valueOf()
:console.log([].valueOf(), typeof [].valueOf()); // [] object
console.log([1, 2].valueOf(), typeof [1, 2].valueOf()); // [ 1, 2 ] object -
function.valueOf()
:console.log(function () {}.valueOf(), typeof function () {}.valueOf()); // [Function (anonymous)] function
-
-
调用
input.toString()
,如果结果是原始类型,则返回这个结果。-
number.toString()
:console.log((1).toString(), typeof (1).toString()); // 1 string
-
string.toString()
:console.log("1".toString(), typeof "1".toString()); // 1 string
-
boolean.toString()
:console.log((true).toString(), typeof (true).toString()); // true string
-
object.toString()
:console.log({}.toString(), typeof {}.toString()); // [object Object] string
console.log({ a: 1 }.toString(), typeof { a: 1 }.toString()); // [object Object] string -
array.toString()
:console.log([].toString(), typeof [].toString()); // "" string
console.log([1, 2].toString(), typeof [1, 2].toString()); // "1,2" string -
function.toString()
:console.log(function () {}.toString(), typeof function () {}.toString()); // "function () {}" string
-
-
抛出
TypeError
异常。
-
-
PreferredType
为string
:-
如果
input
本身就是原始类型,直接返回input
。 -
调用
input.toString()
,如果结果是原始类型,则返回这个结果。-
number.toString()
:console.log((1).toString(), typeof (1).toString()); // 1 string
-
string.toString()
:console.log("1".toString(), typeof "1".toString()); // 1 string
-
boolean.toString()
:console.log((true).toString(), typeof (true).toString()); // true string
-
object.toString()
:console.log({}.toString(), typeof {}.toString()); // [object Object] string
console.log({ a: 1 }.toString(), typeof { a: 1 }.toString()); // [object Object] string -
array.toString()
:console.log([].toString(), typeof [].toString()); // "" string
console.log([1, 2].toString(), typeof [1, 2].toString()); // "1,2" string -
function.toString()
:console.log(function () {}.toString(), typeof function () {}.toString()); // "function () {}" string
-
-
调用
input.valueOf()
,如果结果是原始类型,则返回这个结果。-
number.valueOf()
:console.log((1).valueOf(), typeof (1).valueOf()); // 1 number
-
string.valueOf()
:console.log("1".valueOf(), typeof "1".valueOf()); // 1 string
-
boolean.valueOf()
:console.log((true).valueOf(), typeof (true).valueOf()); // true boolean
-
object.valueOf()
:console.log({}.valueOf(), typeof {}.valueOf()); // {} object
console.log({ a: 1 }.valueOf(), typeof { a: 1 }.valueOf()); // { a: 1 } object -
array.valueOf()
:console.log([].valueOf(), typeof [].valueOf()); // [] object
console.log([1, 2].valueOf(), typeof [1, 2].valueOf()); // [ 1, 2 ] object -
function.valueOf()
:console.log(function () {}.valueOf(), typeof function () {}.valueOf()); // [Function (anonymous)] function
-
-
抛出
TypeError
异常。
-
-
PreferredType
不传入-
如果
input
是内置的Date
类型,PreferredType
视为String
-
否则
PreferredType
视为 ``Number。
-
-
-
ToBoolean ( argument )
Preview -
ToNumber( argument )
Preview -
ToString( argument )
Preview
四、问题
-
({}) + 1
的结果? :-
思路:
+
运算符规则如下加法运算符(
+
)为两种不同的运算重载: 数字加法和字符串连接。在求值时,它首先将两个操作数强制转换为基本类型。然后,检查两个操作数的类型:-
如果有一方是字符串,另一方则会被转换为字符串,并且它们连接起来。
-
如果双方都是
BigInt
,则执行BigInt
加法。如果一方是BigInt
而另一方不是,会抛出TypeError
。 -
否则,双方都会被转换为数字,执行数字加法。
-
-
过程:
{}
和1
都会调用ToPrimitive
,1原始类型直接返回{}
内部调用DefaultNumber
,使用valueOf
方法,返回object
- 在调用
toString
方法,返回[object, object]
- 所以最后的结果就是
[object, object]1
-
-
String({a: 1})
的结果?:- 执行转换
String({a: 1})
- 执行内部的
ToString({a: 1})
{a: 1}
不是原始类型,执行ToPrimitive({a: 1}, hint string)
- 调用
toString
方法,返回"[object, object]"
- 执行
ToString("[object, object]")
,返回"[object, object]"
- 执行转换
-
{} + []
的结果?:-
思路:
+
运算符规则如下加法运算符(
+
)为两种不同的运算重载: 数字加法和字符串连接。在求值时,它首先将两个操作数强制转换为基本类型。然后,检查两个操作数的类型:-
如果有一方是字符串,另一方则会被转换为字符串,并且它们连接起来。
-
如果双方都是
BigInt
,则执行BigInt
加法。如果一方是BigInt
而另一方不是,会抛出TypeError
。 -
否则,双方都会被转换为数字,执行数字加法。
-
-
过程:
-
{} + []
==>{}.ToPrimitive({},default) + [].ToPrimitive([],default)
,[].ToPrimitive([],default)
会尝试调用valueOf()
和toString()
转化成基础类型。由+
运算规则可知, 优先调用valueOf()
-
{} + []
===>{}.valueOf() + [].valueOf()
,{}.valueOf()
结果为{}
,[].valueOf()
结果为[]
, 不为基础类型,继续调用toString()
尝试转化 -
{} + []
===>{}.toString() + [].toString()
,{}.toString()
结果为[object Object]
,[].toString()
结果为""
, 所以结果为[object Object]
-
-
[] + []
的结果?-
思路:
+
运算符规则如下加法运算符(
+
)为两种不同的运算重载: 数字加法和字符串连接。在求值时,它首先将两个操作数强制转换为基本类型。然后,检查两个操作数的类型:-
如果有一方是字符串,另一方则会被转换为字符串,并且它们连接起来。
-
如果双方都是
BigInt
,则执行BigInt
加法。如果一方是BigInt
而另一方不是,会抛出TypeError
。 -
否则,双方都会被转换为数字,执行数字加法。
-
-
过程:
-
[] + []
==>[].ToPrimitive([], default) + [].ToPrimitive([], default)
, 其中[].ToPrimitive([], default)
结果不为基础类型,优先调用[].valueOf()
继续尝试转换基础类型 -
[] + []
==>[].valueOf() + [].valueOf()
, 其中[].valueOf()
结果不为基础类型,继续调用[].toString()
继续尝试转换为基础类型 -
[] + []
==>[].toString() + [].toString()
, 其中[].toString()
结果为""
,所以结果为""
-
-
-
五、总结
-
{}
转换原始数据的过程:-
{}
转换为String
: 类型转换为String
的时候优先调用toString
,如果结果不是原始数据类型,那么继续调用valueOf()
-
result = ToPrimitive({}, String)
,ToPrimitive
的过程-
对象类型
{}
不为原始类型, 优先尝试调用toString()
-
优先尝试调用
{}.toString()
,{}.toString()
结果为字符串类型 "[object,Object]"
, 为原始类型, 返回"[object,Object]"
-
-
得出
result = "[object Object]"
-
-
{}
转换为Number
: 类型转换为Number
的时候优先调用valueOf
,如果结果不是原始数据类型,那么继续调用toString()
-
result = ToPrimitive({}, Number)
,ToPrimitive
的过程-
对象类型
{}
不为原始类型, 优先尝试调用valueOf()
-
优先尝试调用
{}.valueOf()
,{}.valueOf()
结果为对象类型 {}
, 为对象类型, 继续尝试调用{}.toString()
-
继续尝试调用
{}.toString()
,{}.toString()
字符串类型 "[object,Object]"
, 为原始类型, 返回"[object,Object]"
-
-
得出
result = "[object Object]"
-
-
{}
转换为Boolean
: 同上执行过程
-
-
{ a:1 }
转换原始数据的过程:-
{ a:1 }
转换为String
: 类型转换为String
的时候优先调用toString
,如果结果不是原始数据类型,那么继续调用valueOf()
-
result = ToPrimitive({ a:1 }, String)
,ToPrimitive
的过程-
对象类型
{ a:1 }
不为原始类型, 优先尝试调用toString()
-
优先尝试调用
{ a:1 }.toString()
,{ a:1 }.toString()
结果为字符串类型 "[object,Object]"
, 为原始类型, 返回"[object,Object]"
-
-
得出
result = "[object Object]"
-
{ a:1 }
转换为Number
: 类型转换为Number
的时候优先调用valueOf
,如果结果不是原始数据类型,那么继续调用toString()
-
result = ToPrimitive({ a:1 }, Number)
,ToPrimitive
的过程-
对象类型
{ a:1 }
不为原始类型, 优先尝试调用valueOf()
-
优先尝试调用
{ a:1 }.valueOf()
,{ a:1 }.valueOf()
结果为对象类型 { a:1 }
, 为对象类型, 继续尝试调用{}.toString()
-
继续尝试调用
{ a: 1 }.toString()
,{ a:1 }.toString()
字符串类型 "[object,Object]"
, 为原始类型, 返回"[object,Object]"
-
-
得出
result = "[object Object]"
-
-
{ a:1 }
转换为Boolean
: 同上执行过程
-
-
[]
转换原始数据的过程:-
[]
转换为String
: 类型转换为String
的时候优先调用toString
,如果结果不是原始数据类型,那么继续调用valueOf()
-
result = ToPrimitive([], String)
,ToPrimitive
的过程-
对象类型
[]
不为原始类型, 优先尝试调用toString()
-
优先尝试调用
[].toString()
,[].toString()
结果为字符串类型 ""
, 为原始类型, 返回""
-
-
得出
result = ""
-
[]
转换为Number
: 类型转换为Number
的时候优先调用valueOf
,如果结果不是原始数据类型,那么继续调用toString()
-
result = ToPrimitive([], Number)
,ToPrimitive
的过程-
对象类型
[]
不为原始类型, 优先尝试调用valueOf()
-
优先尝试调用
[].valueOf()
,[].valueOf()
结果为对象类型 []
, 为对象类型, 继续尝试调用[].toString()
-
继续尝试调用
[].toString()
,[].toString()
字符串类型 ""
, 为原始类型, 返回""
-
-
得出
result = ""
-
-
[]
转换为Boolean
: 同上执行过程
-
-
[ 1,2 ]
转换原始数据的过程:-
[ 1,2 ]
转换为String
: 类型转换为String
的时候优先调用toString
,如果结果不是原始数据类型,那么继续调用valueOf()
-
result = ToPrimitive([ 1,2 ], String)
,ToPrimitive
的过程-
对象类型
[ 1,2 ]
不为原始类型, 优先尝试调用toString()
-
优先尝试调用
[ 1,2 ].toString()
,[ 1,2 ].toString()
结果为字符串类型 "1,2"
, 为原始类型, 返回"1,2"
-
-
得出
result = "1,2"
-
[ 1,2 ]
转换为Number
: 类型转换为Number
的时候优先调用valueOf
,如果结果不是原始数据类型,那么继续调用toString()
-
result = ToPrimitive([ 1,2 ], Number)
,ToPrimitive
的过程-
对象类型
[ 1,2 ]
不为原始类型, 优先尝试调用valueOf()
-
优先尝试调用
[ 1,2 ].valueOf()
,[ 1,2 ].valueOf()
结果为对象类型 [ 1,2 ]
, 为对象类型, 继续尝试调用[ 1,2 ].toString()
-
继续尝试调用
[ 1,2 ].toString()
,[ 1,2 ].toString()
字符串类型 "1,2"
, 为原始类型, 返回"1,2"
-
-
得出
result = "1,2"
-
-
[ 1,2 ]
转换为Boolean
: 同上执行过程
-
六、方案
6.1 Number(value)
转换
6.2 parseInt(value)
转换
6.3 parseFloat(value)
转换
6.4 +value
加号运算符转换
规则: 除了+
号运算符,其他运算符,只要其中一方数字,那么另一方就被转换为数字。+
运算符规则如下:
- 只要有一边字符串,就把另外一边也转换为字符串,然后拼接
- 两遍都没有字符串,只有有一边为数字,就把另一边转换成数字,然后运算
结果: +
号转换结果同Number
, +(value) === Number(value)
6.5 ~~ value
位移运算符转换
结果: ~~ value
和Number(value)
结果类似,只不过将结果为NaN
的转为0
而已, 并将数字向下取整
-
对于
Number
: 返回自己const value = 9;
console.log(+value); // 9
console.log(Math.floor(+value)); // 9
console.log(~~value); // 9
console.log(Number(value)); // 9
console.log(Math.floor(Number(value))); // 9
const value = 9.8;
console.log(+value); // 9.8
console.log(Math.floor(+value)); // 9
console.log(~~value); // 9
console.log(Number(value)); // 9.8
console.log(Math.floor(Number(value))); // 9 -
对于
String
: 如果字符串都为有效数字字符串,那么返回数字; 只要有一个不为数字字符,返回0
const value = "32a";
console.log(+value); // NaN
console.log(Math.floor(+value)); // NaN
console.log(~~ value); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value))); // NaN
const value = "32";
console.log(+value); // 32
console.log(Math.floor(+value)); // 32
console.log(~~ value); // 32
console.log(Number(value)); // 32
console.log(Math.floor(Number(value))); // 32
const value = " 32 ";
console.log(+value); // 32
console.log(Math.floor(+value)); // 32
console.log(~~ value); // 32
console.log(Number(value)); // 32
console.log(Math.floor(Number(value))); // 32 -
对于
BigInt
类型: 抛出TypeError
,以防止意外的强制隐式转换损失精度。 -
对于
Symbol
类型: 抛出TypeError
-
对于
Object
类型: 返回0
const value = {};
console.log(+value); // NaN
console.log(Math.floor(+value)); // NaN
console.log(~~ value); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value))); // NaN -
对于
Array
类型: 返回0
const value = [];
console.log(+value); // 0
console.log(Math.floor(+value)); // 0
console.log(~~ value); // 0
console.log(Number(value)); // 0
console.log(Math.floor(Number(value))); // 0
const value = [1,2];
console.log(+value); // NaN
console.log(Math.floor(+value)); // NaN
console.log(~~ value); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value))); // NaN
const value = [1];
console.log(+value); // 1
console.log(Math.floor(+value)); // 1
console.log(~~ value); // 1
console.log(Number(value)); // 1
console.log(Math.floor(Number(value))); // 1
6.6 value >> 0
、value >>> 0
位移运算符转换
结果: value >> 0
和Number(value)
结果类似,只不过将结果为NaN
的转为0
而已, 并将数字向下取整
-
对于
Number
: 返回自己const value = 9;
console.log(+value); // 9
console.log(Math.floor(+value)); //9
console.log(value >> 0); // 9
console.log(value >>> 0); // 9
console.log(Number(value)); // 9
console.log(Math.floor(Number(value))); //9
const value = 3.6;
console.log(+value); // 3.6
console.log(Math.floor(+value)); //3
console.log(value >> 0); // 3
console.log(value >>> 0); // 3
console.log(Number(value)); // 3.6
console.log(Math.floor(Number(value))); //3 -
对于
String
: 如果字符串都为有效数字字符串,那么返回数字; 只要有一个不为数字字符,返回0
const value = "32a";
console.log(+value); // NaN
console.log(value >> 0); // 0
console.log(value >>> 0); // 0
console.log(Number(value)); // NaN
const value = "32";
console.log(+value); // 32
console.log(value >> 0); // 32
console.log(value >>> 0); // 32
console.log(Number(value)); // 32
const value = " 32 ";
console.log(+value); // 32
console.log(value >> 0); // 32
console.log(value >>> 0); // 32
console.log(Number(value)); // 32 -
对于
BigInt
类型: 抛出TypeError
,以防止意外的强制隐式转换损失精度。 -
对于
Symbol
类型: 抛出TypeError
-
对于
Object
类型: 返回0
const value = {};
console.log(+value); // NaN
console.log(value >> 0); // 0
console.log(value >>> 0); // 0
console.log(Number(value)); // NaN -
对于
Array
类型: 返回0
const value = [];
console.log(+value); // 0
console.log(value >> 0); // 0
console.log(value >>> 0); // 0
console.log(Number(value)); // 0
const value = [1,2];
console.log(+value); // NaN
console.log(value >> 0); // 0
console.log(value >>> 0); // 0
console.log(Number(value)); // NaN
const value = [8];
console.log(+value); // 8
console.log(value >> 0); // 8
console.log(value >>> 0); // 8
console.log(Number(value)); // 8
6.7 value >> 1
、value >>>
位移运算符转换
结果: 结果同>>value
、>>> value
和Number(value)
结果类似,只不过将结果为NaN
的转为0
而已, 并将数字除以2
且向下取整
-
对于
Number
: 返回自己const value = 9;
console.log(+value); // 9
console.log(Math.floor(+value / 2)); // 4
console.log(value >> 1); // 4
console.log(value >>> 1); // 4
console.log(Number(value)); // 9
console.log(Math.floor(Number(value) / 2)); // 4 -
对于
String
: 如果字符串都为有效数字字符串,那么返回数字; 只要有一个不为数字字符,返回0
const value = "32a";
console.log(+value); // NaN
console.log(Math.floor(+value / 2)); // NaN
console.log(value >> 1); // 0
console.log(value >>> 1); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value) / 2)); // NaN
const value = "32";
console.log(+value); // 32
console.log(Math.floor(+value / 2)); // 16
console.log(value >> 1); // 16
console.log(value >>> 1); // 16
console.log(Number(value)); // 32
console.log(Math.floor(Number(value) / 2)); // 16
const value = " 32 ";
console.log(+value); // 32
console.log(Math.floor(+value / 2)); // 16
console.log(value >> 1); // 16
console.log(value >>> 1); // 16
console.log(Number(value)); // 32
console.log(Math.floor(Number(value) / 2)); // 16 -
对于
BigInt
类型: 抛出TypeError
,以防止意外的强制隐式转换损失精度。 -
对于
Symbol
类型: 抛出TypeError
-
对于
Object
类型: 返回0
const value = {};
console.log(+value); // NaN
console.log(Math.floor(+value / 2)); // NaN
console.log(value >> 1); // 0
console.log(value >>> 1); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value) / 2)); // NaN -
对于
Array
类型: 返回0
const value = [];
console.log(+value); // 0
console.log(Math.floor(+value / 2)); // 0
console.log(value >> 1); // 0
console.log(value >>> 1); // 0
console.log(Number(value)); // 0
console.log(Math.floor(Number(value) / 2)); // 0
const value = [1,2];
console.log(+value); // NaN
console.log(Math.floor(+value / 2)); // NaN
console.log(value >> 1); // 0
console.log(value >>> 1); // 0
console.log(Number(value)); // NaN
console.log(Math.floor(Number(value) / 2)); // NaN
const value = [8];
console.log(+value); // 8
console.log(Math.floor(+value / 2)); // 4
console.log(value >> 1); // 4
console.log(value >>> 1); // 4
console.log(Number(value)); // 8
console.log(Math.floor(Number(value) / 2)); // 4