前言
类型转换一直是 JavaScript 中比较让人头疼的一块内容,虽然这块知识不是很复杂,但是相当之琐碎,本篇文章旨在帮助各位读者老爷系统全面的复习一下 JavaSctipt 中的类型转换。希望各位喜欢。
前置知识
基本数据类型
- number
- string
- boolean
- null
- undefined
- symbol
- bigint
引用数据类型
- 标准普通对象:object以及它下面的分支
- 标准特殊对象:Array、RegExp、Date、Math、Error……
- 非标准特殊对象:Number、String、Boolean……
- 可调用/执行对象「函数」:function
三种类型转换
是的,你没看错,JS 中只存在三种类型转换,分别是转 Number,转 String,转 Boolean。
先来张图
所以后面所有的数据类型转换都可以看做是小学做的连连看。
两种类型转换方法
类型转换方法可以分为两种:隐式类型转换和显式类型转换。
显式类型强制转换是指当开发人员通过编写适当的代码用于在类型之间进行转换,比如:Number(value)。
隐式类型转换是指在对不同类型的值使用运算符时,值可以在类型之间自动的转换,比如 1 == null。
基本数据类型转Boolean
显示转
Boolean()方法可以用来显式将值转换成布尔型
这个比较简单,在JS中只有6种值可以被转换成false,因此我们只要对这6种值进行特殊记忆即可。
这6种值分别是
- false,
- undefined,
- null,
- 0(包括+0,-0),
- "",
- NaN
console.log(Boolean()) // false
console.log(Boolean(false)) // false
console.log(Boolean(undefined)) // false
console.log(Boolean(null)) // false
console.log(Boolean(+0)) // false
console.log(Boolean(-0)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean("")) // false
注意,当 Boolean 函数不传任何参数时,会返回 false。
隐式转
隐式类型转换通常在逻辑判断或者有逻辑运算符时被触发(|| && !)。
// 返回 number 类型 123,而不是 boolean 型 true
// 'hello' 和 '123' 仍然在内部会转换成 boolean 型来计算表达式
let x = 'hello' && 123 // x === 123
boolean 类型转换只会有 true 或者 false 两种结果。除了“0/NaN/空字符串/null/undefined”五个值是false,其余都是true
基本数据类型转Number
参考这张表
| 参数类型 | 结果 |
|---|---|
| Undefined | NaN |
| Null | +0 |
| Boolean | 如果参数是 true,返回 1。参数为 false,返回 +0 |
| Number | 返回与之相等的值 |
| String | 这段比较复杂,看例子 |
| Symbol | 报错 |
| bigInt | 不能通过+隐式转换,只能通过Number显示转换,忽略n |
显示转
Number(),parseInt(),parseFloat()方法可以用来显式将值转换成数字类型。
举几个例子
console.log(Number()) // +0
console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0
console.log(Number(false)) // +0
console.log(Number(true)) // 1
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
console.log(Number(Symbol()))//Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(Number(12312412321312312n)) //12312412321312312
从上面的例子可以看出前四种转换都比较简单。就是字符串转Number这里有些复杂,因此我们也重点讲一下字符串转Number.
字符串转Number遵循的规则是
- 空字符串直接返回0
- 忽略所有前导的 0,除非前面是0x代表的16进制。
- 转换成一个整数或浮点数
- 如果有一个字符不是数字,结果都会返回 NaN
而通过Number的这种转换太过严格,因此我一般还会使用更加灵活的 parseInt 和 parseFloat 进行转换。
parseInt 只解析整数,parseFloat 则可以解析整数和浮点数,如果字符串前缀是 "0x" 或者"0X",parseInt 将其解释为十六进制。
两者共同的转换规则
- parseInt 和 parseFloat 都会跳过任意数量的前导空格
- 尽可能解析更多数值字符
- 并忽略后面的内容
- 如果第一个非空格字符是非法的数字直接量,将最终返回 NaN:
看例子
console.log(parseInt("3 abc")) // 3
console.log(parseFloat("3.14 abc")) // 3.14
console.log(parseInt("-12.34")) // -12
console.log(parseInt("0xFF")) // 255
console.log(parseFloat(".1")) // 0.1
console.log(parseInt("0.1")) // 0
隐式转
number 的隐式类型转换是比较复杂的,因为它可以在下面多种情况下被触发。
- 比较操作(>, <, <=, >=)
- 按位操作(| & ^ ~)
- 算数操作(- + * / %), 注意:当 + 操作存在任意的操作数是 string 类型时,不会触发 number 类型的隐式转换
- 一元 + 操作
基本数据类型转String
参考这张表
| 参数类型 | 结果 |
|---|---|
| Undefined | "undefined" |
| Null | "null" |
| Boolean | 如果参数是 true,返回 "true"。参数为 false,返回 "false" |
| Number | 又是比较复杂,可以看例子 |
| String | 返回与之相等的值 |
| Symbol | 不能通过+隐式转换,只能通过toString显示转换,返回字符串 |
| BigInt | 返回去掉n的数字字符串 |
显式转
String()方法可以用来显式将值转为字符串。
举几个例子
console.log(String()) // 空字符串
console.log(String(undefined)) // undefined
console.log(String(null)) // null
console.log(String(false)) // false
console.log(String(true)) // true
console.log(String(0)) // 0
console.log(String(-0)) // 0
console.log(String(NaN)) // NaN
console.log(String(Infinity)) // Infinity
console.log(String(-Infinity)) // -Infinity
console.log(String(1)) // 1
同样的,难啃的骨子还是在Number与String的转换上。
隐式转
隐式转换通常在有 + 运算符并且有一个操作数是 string 类型时被触发
“+”代表的字符串拼接,如果下面的情况存在时会触发转换
- 有两边,一边是字符串,则会变成字符串拼接;
- 有两边,一边是对象
1 + '123' //"1123"
1 + {} //"1[object Object]"
对象转数字
- 如果对象具有 valueOf 方法,且返回一个原始值,则 JavaScript 将这个原始值转换为数字并返回这个数字
- 否则,如果对象具有 toString 方法,且返回一个原始值,则 JavaScript 将其转换并返回。
- 否则,JavaScript 抛出一个类型错误异常。
对象转字符串
- 如果对象具有 toString 方法,则调用这个方法。如果他返回一个原始值,JavaScript 将这个值转换为字符串,并返回这个字符串结果。
- 如果对象没有 toString 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf 方法。如果存在这个方法,则 JavaScript 调用它。如果返回值是原始值,JavaScript 将这个值转换为字符串,并返回这个字符串的结果。
- 否则,JavaScript 无法从 toString 或者 valueOf 获得一个原始值,这时它将抛出一个类型错误异常。
toString,valueOf以及ToPrimitive
toString
所有的对象除了 null 和 undefined 之外的任何值都具有 toString 方法,通常情况下,它和使用 String 方法返回的结果一致。toString 方法的作用在于返回一个反映这个对象的字符串,然而这才是情况复杂的开始。
Object.prototype.toString 方法会根据这个对象的[[class]]内部属性,返回由 "[object " 和 class 和 "]" 三个部分组成的字符串。举个例子:
Object.prototype.toString.call({a: 1}) // "[object Object]"
({a: 1}).toString() // "[object Object]"
({a: 1}).toString === Object.prototype.toString // true
我们可以看出当调用对象的 toString 方法时,其实调用的是 Object.prototype 上的 toString 方法。
然而 JavaScript 下的很多类根据各自的特点,定义了更多版本的 toString 方法。例如:
- 数组的 toString 方法将每个数组元素转换成一个字符串,并在元素之间添加逗号后合并成结果字符串。
- 函数的 toString 方法返回源代码字符串。
- 日期的 toString 方法返回一个可读的日期和时间字符串。
- RegExp 的 toString 方法返回一个表示正则表达式直接量的字符串。
读文字太抽象?我们直接写例子:
console.log(({}).toString()) // [object Object]
console.log([].toString()) // ""
console.log([0].toString()) // 0
console.log([1, 2, 3].toString()) // 1,2,3
console.log((function(){var a = 1;}).toString()) // function (){var a = 1;}
console.log((/\d+/g).toString()) // /\d+/g
console.log((new Date(2010, 0, 1)).toString()) // Fri Jan 01 2010 00:00:00 GMT+0800 (CST)
valueOf
表示对象的原始值。默认的 valueOf 方法返回这个对象本身,数组、函数、正则简单的继承了这个默认方法,也会返回对象本身。日期是一个例外,它会返回它的一个内容表示: 1970 年 1 月 1 日以来的毫秒数。
var date = new Date(2017, 4, 21);
console.log(date.valueOf()) // 1495296000000
ToPrimitive
ToPrimitive(input[, PreferredType])
第一个参数是 input,表示要处理的输入值。
第二个参数是 PreferredType,非必填,表示希望转换成的类型,有两个值可以选,Number 或者 String。
当不传入 PreferredType 时,如果 input 是日期类型,相当于传入 String,否则,都相当于传入 Number。
如果传入的 input 是 Undefined、Null、Boolean、Number、String 类型,直接返回该值。
如果是 ToPrimitive(obj, Number),处理步骤如下:
- 如果 obj 为 基本类型,直接返回
- 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
- 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
- 否则,JavaScript 抛出一个类型错误异常。
如果是 ToPrimitive(obj, String),处理步骤如下:
- 如果 obj为 基本类型,直接返回
- 否则,调用 toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
- 否则,调用 valueOf 方法,如果返回一个原始值,则 JavaScript 将其返回。
- 否则,JavaScript 抛出一个类型错误异常。
结语
JS的类型转换的逻辑无论在原始类型和对象类型上,他们都只会转换成上面 3 种类型之一。所以只需要弄清在什么场景下应该转成哪种类型就可以了。
-
所有数据类型转Boolean,除了0,null,undefined,"",NaN,false这6种会被转换为false,以外,都会变成true。
-
基本数据类型转Number,参考这张表 | 参数类型 | 结果 | | - | - | | Undefined | NaN | | Null | +0 | | Boolean | 如果参数是 true,返回 1。参数为 false,返回 +0 | | Number | 返回与之相等的值 | | String | 这段比较复杂,看例子 | | Symbol| 报错 | | bigInt| 不能通过+隐式转换,只能通过Number显示转换,忽略n |
-
引用数据类型转Number,参考这个规则
- 如果对象具有 valueOf 方法,且返回一个原始值,则 JavaScript 将这个原始值转换为数字并返回这个数字
- 否则,如果对象具有 toString 方法,且返回一个原始值,则 JavaScript 将其转换并返回。
- 否则,JavaScript 抛出一个类型错误异常。
-
基本数据类型转String,参考这张表 | 参数类型 | 结果 | | - | - | | Undefined | "undefined" | | Null | "null" | | Boolean | 如果参数是 true,返回 "true"。参数为 false,返回 "false" | | Number | 又是比较复杂,可以看例子 | | String | 返回与之相等的值 | | Symbol | 不能通过+隐式转换,只能通过toString显示转换,返回字符串 | | BigInt | 返回去掉n的数字字符串|
-
基本数据类型转String,参考这个规则
- 如果对象具有 toString 方法,则调用这个方法。如果他返回一个原始值,JavaScript 将这个值转换为字符串,并返回这个字符串结果。
- 如果对象没有 toString 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf 方法。如果存在这个方法,则 JavaScript 调用它。如果返回值是原始值,JavaScript 将这个值转换为字符串,并返回这个字符串的结果。
- 否则,JavaScript 无法从 toString 或者 valueOf 获得一个原始值,这时它将抛出一个类型错误异常。