JavaScript中检测数据类型的方法有那些?
JavaScript中数据类型有那些?
JavaScript中的数据类型包括原始类型和对象类型
原始类型:
- String
- Number
- Boolean
- Null
- Undefined
- BigInt
- Symbol
引用类型:
Object
特殊的引用类型有:
- Function
- Array
- RegExp
- Date
- Math
- Error
- Set
- Map
- 等等
JavaScript中检测数据类型的方法有哪些?
一共有四种:
- typeof
- instanceof
- constructor
- Object.prototype.toString.call()
typeof
typeof 'a' // 'string'
typeof 1 // 'number'
typeof NaN // 'number'
typeof true // 'boolean'
typeof null // 'object'
typeof undefined // 'undefined'
typeof Symbol('a') // 'symbol'
typeof 1ln // binint
typeof function(){} // 'function'
typeof [] // 'object'
typeof {} // 'object'
typeof /a/ // 'object'
typeof new Date() // 'object'
typeof new Error() // 'object'
typeof new Map() // 'object'
typeof new Set() // 'object'
以上可以看出:
- typeof 可以判断除了 **null ** 以为的原始类型
- typeof只能判断对象类型中的Function,其他的都为object
为什么 typeof null 的值是object呢?
typeof 检测null 时返回object,是最初JavaScript语言的一个bug,为了兼容老的代码,一直保留至今
这里 NaN也是一个特殊存在
instanceof
console.log(1 instanceof Number) // false
console.log(new Number(1) instanceof Number) // true
const arr =[]
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true
const Fn = funciton(){
this.name = '构造函数'
}
Fn.prototype = Object.create(Array.prototype)
let a = new Fn()
console.log(a instanceof Array) // true
instanceof 用来检测构造函数的prototype属性是否出现在某个实例对象的原型链上,也就是使用 a instanceof B 判断的是:a是否是 B的实例,既a的原型链上是否存在B的构造函数
结论:
- instanceof 可以准确判断对象(引用)类型,但是不能准确检测原始类型
- 由于我们可以随意修改原型的指向导致检测结果不准确,所以这种方法是不安全的
如果我就想用instanceof检测原始类型呢,可以实现吗?
我们可以用Symbol.hasInstance 来定义instanceof的行为
class PrimitiveNumber {
static [Symbol.hasInstance] = x => typeof x === 'number'
}
123 instanceof PrimitiveNumber // true
class PrimitiveString {
static [Symbol.hasInstance] = x => typeof x === 'string'
}
'str' instanceof PrimitiveString // true
class PrimitiveBoolean {
static [Symbol.hasInstance] = x => typeof x === 'boolean'
}
false instanceof PrimitiveBoolean // true
class PrimitiveSymbol {
static [Symbol.hasInstance] = x => typeof x === 'symbol'
}
Symbol.iterator instanceof PrimitiveSymbol // true
class PrimitiveNull {
static [Symbol.hasInstance] = x => typeof x === null
}
null instanceof PrimitiveNull // true
class PrimitiveUndefined {
static [Symbol.hasInstance] = x => typeof x === undefined
}
undefined instanceof PrimitiveUndefined // true
那你可以手写instanceof吗?
const myInstanceof = funtion(left,right){
if(typeof left !== 'object' || left === null) return false
let proto = Reflect.getPrototypeOf(left)
while(true){
if(proto === null) return false
if(proto === right.prototype) return true
proto = Reflect.getPrototypeOf(proto)
}
}
const arr =[]
console.log(myInstanceof(arr,Array)) // true
console.log(myInstanceof(arr,Object)) // true
console.log(myInstanceof(arr,RegExp)) // false
Constructor
const a = '测试'
console.log(a.constructor) // ƒ String() { [native code] }
console.log(a.constructor === String) // true
const b = 5
console.log(b.constructor) // ƒ Number() { [native code] }
console.log(b.constructor === Number) // true
const c = true
console.log(c.constructor) // ƒ Boolean() { [native code] }
console.log(c.constructor === Boolean) // true
const d = []
console.log(d.constructor) // ƒ Array() { [native code] }
console.log(d.constructor === Array) // true
const e = {}
console.log(e.constructor) // ƒ Object() { [native code] }
console.log(e.constructor === Object) // true
const f = () => 1
console.log(f.constructor) // ƒ Function() { [native code] }
console.log(f.constructor === Function) // true
const g = Symbol('1')
console.log(g.constructor) // ƒ Symbol() { [native code] }
console.log(g.constructor === Symbol) // true
const i = new Date()
console.log(i.constructor) // ƒ Date() { [native code] }
console.log(i.constructor === Date) // true
const j = 1ln
console.log(j.constructor) // ƒ BigInt() { [native code] }
console.log(j.constructor === BigInt) // true
const k = /a/
console.log(k.constructor) // ƒ RegExp() { [native code] }
console.log(k.constructor === RegExp) // true
const k = null
console.log(k.constructor) // Cannot read properties 'constructor' of null
console.log(k.constructor === RegExp) // true
const l = undefined
console.log(l.constructor) // Cannot read properties 'constructor' of undefined
// 所以需要加上一个小括号,小括号运算符能够把数值转换为对象
(1).constructor // ƒ Number() { [native code] }
// 或者
1..constructor // ƒ Number() { [native code] }
对于数值直接量,直接使用constructor 是会报错的,这个错误来自于浮点数的字面量解析过程,而不是“.”作为存取运算符的处理过程
在js中,浮点数的小数位是可以为空的,因此1.或者1.0会解析成相同的浮点数
所以需要加一个小括号,小括号运算符能够把数值转换为对象
结论:
- 除了null和undefined,constructor 可以检测出原始类型和对象引用类型
- 由于我们可以随意修改 constructor 导致检测结果不准确,所以这种方法是不安全的
Object.prototype.toString.call()
Object.prototype.toString({}) // '[object Object]'
Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call('a') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(Symbol('a')) // '[object Symbol]'
Object.prototype.toString.call(1ln) // '[object BigInt]'
Object.prototype.toString.call(/a/) // '[object RegExp]'
Object.prototype.toString.call(new Dyae()) // '[object Date]'
Object.prototype.toString.call([0,1,2]) // '[object Array]'
Object.prototype.toString.call(function(){}) // '[object Function]'
Object.prototype.toString.call(new Error()) // '[object Error]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new Map()) // '[object Map]'
toSting()方法返回一个表示该对象的字符串,我们可以改变它的this指向,将this指向要检测的值,即可返回当前检测值的信息
来源于B站学习-前端食堂 个人感觉讲的不错,并手打出来,方便自己和大家共通学习~