在JavaScript中,有String,Number,Null,Undefined,Boolean,Object,Symbol,BigInt八种数据类型,在Object中,又包含普通对象,Array,RegExp,Date,Function等几种很常见的引用数据类型。
JavaSript中的数据类型检测
| 方法 | 说明 |
|---|---|
| typeof [value] | 用来检测数据类型的运算符 |
| instanceof | 用来检测当前实例是否属于某个类 |
| Object.prototype.toString | 检测数据类型的最好办法 |
typeof
基于typeof检测出来的结果
- 首先这个结果是一个字符串
- 字符串中包含数据类型
typeof的局限性:
typeof null结果是object,但是null并不是对象,这是JavaScript存在的很久远的一个bug- 对于
引用数据类型的值,除了function,其他对象类型使用typeof检测的结果都是object,无法知道具体是哪个引用数据类型(Object/Array/RegExp/Date)的值
typeof null 'object'
typeof function(){} 'function'
typeof {} 'object'
typeof [] 'object'
typeof /\d/ 'object'
基于typeof检测的结果都是字符串,所以只要两个及以上同时检测,最后结果必然是'string'
typeof typeof typeof [] // 'string'
instanceof
- instanceof是基于原型链查询
- 可以准确判断
引用类型的数据类型 - 不能正确判断基础数据类型
核心原理实现
function myInstanceof(left, right) {
// 如果判断的是基础数据类型,就直接返回false
if(typeof left !== 'object' || left === null) return false
let proto = Object.getPrototypeOf(left)
while(true) {
// 如果已经找到了尽头还没有找到,就返回false
if(proto === null) return false
// 如果找到原型对象就返回true
if(proto === right.prototype) return true
proto = Object.getPrototypeOf(proto)
}
}
Object.prototype.toString
Object.prototype.toString方法返回[object Type]这个字符串,可以更准确展示当前数据类型
const string = 'string' // "[object String]"
const number = 88 // "[object Number]"
const nul = null // "[object Null]"
const und = undefined // "[object Undefined]"
const bol = true // "[object Boolean]"
const symbol = Symbol('symbol') // "[object Symbol]"
const bigInt = BigInt(1) // "[object BigInt]"
const obj = {} // "[object Object]"
const arr = [] // "[object Array]"
const reg = /\d+/ // "[object RegExp]"
const date = new Date() // "[object Date]"
const fn = function(){} // "[object Function]"
JavaSript中的数据类型转换
JS中类型转换分为强制类型转换和隐式类型转换。
-
通过
Number()、parseInt()、parseFloat()、toString()、String()、Boolean()进行强制类型转换。 -
逻辑运算符(
&&、||、!)、运算符(+、-、*、/)、关系操作符(>、 <、 <= 、>=)、相等运算符(==)或者if/while的条件,可能会进行隐式类型转换。
原始值转数字
我们使用Number函数将原始值转为数字,如果不传参数,返回+0,有参数时会调用底层的ToNumber方法
ToNumber方法具体传值类型和结果如下表:
| 参数类型 | 结果 |
|---|---|
| Undefined | NaN |
| Null | 0 |
| Boolean | 如果参数是 true,返回 1。参数为 false,返回 0 |
| Number | 返回自身 |
| String | 如下 |
Number('007')
Number('12.3') // 12.3
Number('12.00') // 12
Number('123e-1') // 12.3
Number('') // 0
Number('0x11') // 17
Number('0b11') // 3
Number('0o11') // 9
Number('foo') // NaN
Number('100a') // NaN
Number(Infinity) // Infinity
Number('-Infinity') //-Infinity
-
字符串中只包含数字,则将数字转换为十进制数字
-
字符串中包含有效浮点格式,将其转换为浮点数值
-
空字符串转换为0
-
不是以上格式都返回
NaN
数字包含常规数字和NaN
NaN
- not a number,不是一个数,但是它属于数字类型
NaN和任何值(包括自己)都不相等
- isNaN(val)
检测一个值是否为非有效数字,不是有效数字返回
true,是有效数字返回false
isNaN('AA') // true
isNaN(10) // false
isNaN('22') // false
在使用isNaN检测值的时候,首先会验证检测的值是否为number类型,如果不是,先基于Number方法,将值转换为number类型,然后再进行检测
原始值转字符串
我们使用String函数将其他原始类型转为字符串,如果不传参数,空字符串,有参数时会调用底层的ToString方法
ToString方法具体传值类型和结果如下表:
| 参数类型 | 结果 |
|---|---|
| Undefined | 'undefined' |
| Null | 'null' |
| Boolean | 如果参数是 true,返回 'true'。参数为 false,返回 'false' |
| Number | 如下 |
| String | 返回自身 |
String(0) // "0"
String(88) // "88"
String(-22) // "-22"
String(NaN) // "NaN"
String(Infinity) // "Infinity"
String(-Infinity) // "-Infinity"
原始值转布尔
只有0,NaN, undefined ,null ,'',false六个值转换为false,其他都转换为true
Boolean(0) // false
Boolean(NaN) // false
Boolean(undefined) // false
Boolean(null) // false
Boolean('') // false
Boolean(false) // false
原始值转对象
除了null和undefined,调用各自包装函数转换为各自的包装对象
对象转数字和字符串
对象转数字和字符串主要参照对象的toString方法和valueOf方法。
valueOf方法一般返回对象本身,但是对于Date例外,它会返回一个表示1970年1月1日以来的毫秒数
({}).valueOf() // {}
([]).valueOf() // []
(/\d+/).valueOf() // /\d+/
(function foo(){}).valueOf() //function foo(){}
(new Date('2020-02-02')).valueOf() // 1580601600000
-
对于
toString方法来说,不同类型的对象调用toString方法的返回值不同-
普通对象调用toString,返回"[object Object]" -
数组调用toString,返回一个数组元素以逗号拼接的字符串 -
函数调用toString,返回源代码字符串 -
日期调用toString,返回一个可读的日期和时间字符串 -
RegExp调用toString,返回一个正则表达式字符串
-
({}).toString() // "[object Object]"
([]).toString() // ""
([1, 2, 3]).toString() // "1,2,3"
(function(){}).toString() // "function(){}"
(/\d+/g).toString() // "/\d+/g"
(new Date(2020, 02, 02)).toString() // "Mon Mar 02 2020 00:00:00 GMT+0800 (中国标准时间)"
将对象转为字符串/数字的时候,默认会调用底层ToPrimitive方法
ToPrimitive(input[, PreferredType])
-
第一个参数input,表示要处理的值
-
第二个参数PreferredType,如果
input是日期类型,相当于传入String,否则,都相当于传入Number -
如果传入的input是原始类型,就返回自身
如果是ToPrimitive(obj, Number)
- 如果
obj是原始类型的值,就直接返回自身 - 否则,调用
valueOf方法,如果返回的是原始类型的值,就将其返回 - 否则,调用
toString方法,如果返回的是原始类型的值,就将其返回 - 否则,跑出一个类型异常错误
如果是ToPrimitive(obj, String)
- 如果
obj是原始类型的值,就直接返回自身 - 否则,调用
toString方法,如果返回的是原始类型的值,就将其返回 - 否则,调用
valueOf方法,如果返回的是原始类型的值,就将其返回 - 否则,抛出一个类型异常错误
对象转数字
-
调用对象的
valueOf方法,如果返回的是原始类型的值,就按照上面的原始值转数字方法将这个值转为数字并返回 -
否则,调用对象的
toString方法,如果返回的是原始类型的值,就按照上面的原始值转数字方法将这个值转为数字并返回 -
否则,抛出一个类型异常错误
对象转字符串
-
调用对象的
toString方法,如果返回的是原始类型的值,就按照上面的原始值转字符串方法将这个值转为字符串并返回 -
否则,调用对象的
valueOf方法,如果返回的是原始类型的值,就按照上面的原始值转字符串方法将这个值转为字符串并返回 -
否则,抛出一个类型异常错误
Number({}) // NaN
String({}) // 'object Object'
Number({})
-
调用
{}的valueOf方法,返回{},不是原始类型,继续调用{}的toString方法 -
调用
{}的toString方法,返回[object Object]字符串,符合原始类型,按照字符串转数字规则,返回NaN
对象转布尔
所有对象都转换布尔都为true