JavaScript中检测数据类型的方法有那些?

236 阅读3分钟

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站学习-前端食堂 个人感觉讲的不错,并手打出来,方便自己和大家共通学习~