概述
JavaScript 是一种弱类型动态类型语言,变量没有类型限制,可以随时赋予任意值。
var x = y ? 1 : 'a';
上面代码中,变量x
到底是数值还是字符串,取决于另一个变量y
的值。y
为true
时,x
是一个数值;y
为false
时,x
是一个字符串。这意味着,x
的类型没法在编译阶段就知道,必须等到运行时才能知道。
虽然变量的数据类型是不确定的,但是各种运算符对数据类型是有要求的。如果运算符发现,运算子的类型与预期不符,就会自动转换类型。比如,减法运算符预期左右两侧的运算子应该是数值,如果不是,就会自动将它们转为数值。
'4' - '3' // 1
上面代码中,虽然是两个字符串相减,但是依然会得到结果数值1
,原因就在于 JavaScript 将运算子自动转为了数值。
一、强制类型转换(显式类型转换)
强制转换主要指使用Number()
、String()
和Boolean()
三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。
(1)Number()
使用Number
函数,可以将任意类型的值转化成数值。
(a)原始类型
原始类型值的转换规则如下。
// 数值:转换后还是原来的值 Number(324) // 324 // 字符串:如果可以被解析为数值,则转换为相应的数值 Number('324') // 324 // 字符串:如果不可以被解析为数值,返回 NaN Number('324abc') // NaN // 空字符串转为0 Number('') // 0 // 布尔值:true 转成 1,false 转成 0 Number(true) // 1 Number(false) // 0 // undefined:转成 NaN Number(undefined) // NaN // null:转成0 Number(null) // 0
Number
函数将字符串转为数值,要比parseInt
函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN
。
parseInt('42 cats') // 42 Number('42 cats') // NaN
上面代码中,parseInt
逐个解析字符,而Number
函数整体转换字符串的类型。
另外,parseInt
和Number
函数都会自动过滤一个字符串前导和后缀的空格。
parseInt(' v 12.34 ') // 12 Number(' v 12.34 ') // 12.34
(b)引用类型: 真实对象、数组、Date()
Number方法的参数是真实对象时,将返回NaN,
Number方法的参数是数组时,
当数组为空数组时,返回0;
当数组不为空数组时,只有该数组是单项数组,且单项可以使用Number转换为数字,最终该数组转换的值就是对该单项使用Number转换的值;其他均返回NaN
Number方法的参数是Date类型时,返回的当前时间到1970年1月1日的毫秒
console.log(Number({ a: 1 })) // NaN console.log(Number({})) // NaN console.log(Number([1, 2, 3])) // NaN console.log(Number([5])) // 5 console.log(Number(['2'])) // 1 console.log(Number([])) // 0 console.log(Number([""])) // 0 console.log(Number(["avb"])) // NaN console.log(Number(["123avb"])) // NaN console.log(Number(new Date())); // 1614748084424
之所以会这样,是因为Number
背后的转换规则比较复杂。
- 第一步,调用对象自身的
valueOf
方法。如果返回原始类型的值,则直接对该值使用Number
函数,不再进行后续步骤。 - 第二步,如果
valueOf
方法返回的还是对象,则改为调用对象自身的toString
方法。如果toString
方法返回原始类型的值,则对该值使用Number
函数,不再进行后续步骤。 - 第三步,如果
toString
方法返回的是对象,就报错。
请看下面的例子
var obj = {x: 1}; Number(obj) // NaN // 等同于 if (typeof obj.valueOf() === 'object') { Number(obj.toString()); } else { Number(obj.valueOf()); }
上面代码中,Number
函数将obj
对象转为数值。背后发生了一连串的操作,首先调用obj.valueOf
方法, 结果返回对象本身;于是,继续调用obj.toString
方法,这时返回字符串[object Object]
,对这个字符串使用Number
函数,得到NaN
。
默认情况下,对象的valueOf
方法返回对象本身,所以一般总是会调用toString
方法,而toString
方法返回对象的类型字符串(比如[object Object]
)。所以,会有下面的结果。
Number({}) // NaN
如果toString
方法返回的不是原始类型的值,结果就会报错。
var obj = { valueOf: function () { return {}; }, toString: function () { return {}; } }; Number(obj) // TypeError: Cannot convert object to primitive value
上面代码的valueOf
和toString
方法,返回的都是对象,所以转成数值时会报错。
从上例还可以看到,valueOf
和toString
方法,都是可以自定义的。
Number({ valueOf: function () { return 2; } }) // 2 Number({ toString: function () { return 3; } }) // 3 Number({ valueOf: function () { return 2; }, toString: function () { return 3; } }) // 2
上面代码对三个对象使用Number
函数。第一个对象返回valueOf
方法的值,第二个对象返回toString
方法的值,第三个对象表示valueOf
方法先于toString
方法执行。
二、String()
String
函数可以将任意类型的值转化成字符串,转换规则如下。
(a)原始类型值
- 数值:转为相应的字符串。
- 字符串:转换后还是原来的值。
- 布尔值:
true
转为字符串"true"
,false
转为字符串"false"
。 undefined
:转为字符串"undefined"
。null
:转为字符串"null"
。
String(123) // "123" String('abc') // "abc" String(1e21) // '1e+21' String(true) // "true" String(undefined) // "undefined" String(null) // "null"
(b)对象
String
方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式,相当于调用数组的Array.prototype.join()
方法。String({a: 1}) // "[object Object]" // 空数组[]转为空字符串 String([]) // '' String([1, 2, 3]) // "1,2,3" // 数组中的null或undefined,会被当做空字符串处理 String([1, undefined, 3]) // '1,,3'
String
方法背后的转换规则,与Number
方法基本相同,只是互换了valueOf
方法和toString
方法的执行顺序。
1、先调用对象自身的toString
方法。如果返回原始类型的值,则对该值使用String
函数,不再进行以下步骤。
2、如果toString
方法返回的是对象,再调用原对象的valueOf
方法。如果valueOf
方法返回原始类型的值,则对该值使用String
函数,不再进行以下步骤。
3、如果valueOf
方法返回的是对象,就报错。
下面是一个例子
String({a: 1}) // "[object Object]" // 等同于 String({a: 1}.toString()) // "[object Object]"
上面代码先调用对象的toString
方法,发现返回的是字符串[object Object]
,就不再调用valueOf
方法了。
如果toString
法和valueOf
方法,返回的都是对象,就会报错。
var obj = { valueOf: function () { return {}; }, toString: function () { return {}; } }; String(obj) // TypeError: Cannot convert object to primitive value
三、Boolean()
Boolean()
函数可以将任意类型的值转为布尔值。
它的转换规则相对简单:除了以下五个值的转换结果为false
,其他的值全部为true
。
undefined
null
0
(包含-0
和+0
)NaN
''
(空字符串)
Boolean(undefined) // false Boolean(null) // false Boolean(0) // false Boolean(NaN) // false Boolean('') // false
当然,true
和false
这两个布尔值不会发生变化。
Boolean(true) // true Boolean(false) // false
注意,所有对象(包括空对象)的转换结果都是true
,甚至连false
对应的布尔对象new Boolean(false)
也是true
。
Boolean({}) // true Boolean([]) // true Boolean(new Boolean(false)) // true
参考:
https://www.jianshu.com/p/d9bd0599cb99
https://blog.csdn.net/weixin_42733155/article/details/85879624
https://www.jb51.net/article/122519.htm
https://www.cnblogs.com/mengxiangji/p/11080006.html
https://www.php.cn/js-tutorial-393272.html
https://www.it610.com/article/1290454860726083584.htm