JS 的数据类型转换
JS 是一种动态类型语言, 变量的数据类型在运行时才确定,并且在运行时还是可变的,而不是像C系,JAVA那样,在写代码时(编译时)就确定类型了。
在进行数值运算/比较时,JS 会自动转换类型。当然,我们也可以手动转换类型。
强制(显式)类型转换
Number 函数
Number 函数可以进行强制类型转换,需注意以下这些转换规则:
js
// 1. *纯数字字符串*转换为对应的 数字
Number('324') // 324
Number('0000123') // 123
// 2. *非纯数字字符串*转换为 NaN
Number('324abc') // NaN
Number('0-123') // NaN
// 3. *空字符串以及带转义字符的空字符串*转换为 0
Number('') // 0
Number(' \n \t \r ') // 0
Number(' 123') // 123 (前导空格被忽略)
// 4. *true 1 , false 0*
Number(true) // 1
Number(false) // 0
// 5. undefined NaN, null 0
Number(undefined) // NaN
Number(null) // 0❓ parseInt, parseFloat 与 Number 的区别
前两者都是自左向右逐字符解析,而 Number 是全串匹配
parseInt 还有第二个参数radix,可以进行进制转换
js
// parseInt
parseInt("123abc"); // 123 OK的
parseInt("10", 2); // 2 按二进制解析
parseInt("abc123"); // NaN
parseInt(" 42 "); // 42 (前导空格被忽略)
// parsefloat
parseFloat("3.14abcd"); // 3.14 ✅
parseFloat("abc123.4"); // NaN ❌❓ Number(obj)会发生什么
简单来说:除非obj是一个包含单个数值的数值,否则 Number(obj) 总是返回NaN
具体来说,再 Number(obj) 时, 依次会发生:
- 调用
obj.valueOf(), 如果返回值原始类型,直接对该值使用Number函数 - 如果返回的还是对象类型,那就调用
obj.toString(),如果返回值原始类型,直接对该值使用Number函数,一般就是到这一步,最终返回值为NaN - 如果返回的还是对象类型,那会报错
js
// 测试
const obj = {'a' : '1'}
obj.toString = ()=>{
return obj
}
console.log(Number(obj))
// Uncaught TypeError: Cannot convert object to primitive valueString 函数
String 非常强悍,可以把任意值转为字符串, 主要体现为以下:
js
String(123) // "123"
String('abc') // "abc"
// true, false, undefined, null 都变为字面量字符串
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
// 数组比较特殊,数组的 toString方法会把所有元素用 ,连接起来作为字符串
String([1, 2, 3]) // "1,2,3"
// 对象变为 [object Object],同样是先调用 valueOf, 再调用 toString
String({}) // '[object Object]'Boolean 函数
除了以下五个值的转换结果为false,其他的值全部为true,在运算符章节中详细描述过
- undefined
- null
- 0(包含-0和+0)
- NaN
- ''(空字符串)
自动(隐式)类型转换
自动类型转换具有不确定性,正式应用时,最好显示转换一下
主要场景:
不同数据类型运算
条件判断时自动转bool
对非数值类型使用
+-具体可参考章节运算符
包装对象/装箱机制
三种原始类型的值数值、字符串、布尔值在一定条件下,也会自动转为“包装对象”(wrapper),这也是一些教程里说的 JS 的装箱机制(boxing)。
包装对象实现了运行时一切皆对象,让原始类型的值也能调用原型上的方法。
js
var str = 'abc';
console.log(str.length) // 3
// 等同于
var strObj = new String(str)
// String {
// 0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"
// }
console.log(strObj.length)调用结束后,包装对象实例会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性,除非把新属性放在原型上。
js
var s = 'Hello World';
s.x = 'x';
console.log(s.x) // undefined
s.__proto__.y = 'y'
console.log(s.y)