JavaScript 数据类型的判断

简介

为了巩固一下身为前端开发小菜鸟必备的脸面,从而让脸皮更加厚实一些,在这条道路活的更加滋润一些,故此开始整理一些JavaScript(脸面)使用的一些基础细节。
欢迎各位大牛莅临指导,从而让我在加厚脸皮的道路上走的更远,从而可以用脸皮挡子弹,挡导弹,挡核弹,然后无敌。哈哈哈!
现在从最基本的数据类型的判断开始。

数据类型

先了解一下JavaScript中的数据类型包含哪些,主要有下述几种

  • String
  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt
  • Symbol
  • Object
    • Array
    • Date
    • RegExp
    • Map
    • WeakMap
    • Set
    • FormData
    • Function
    • Math

前面七种我们称呼为基本数据类型(简单数据类型),最后一种(Object)为引用数据类型(复杂数据类型)。而引用数据类型包含Array-数组对象、Date-日期对象、RegExp-正则对象、Map对象、WeakMap对象、Set-集合对象、FormData-表单对象、Function-函数对象、Math-数学函数等。

在这之前,我们先来了解一下JavaScript中的栈内存和堆内存。
在其他常见的语言中,用来保存变量和对象的内存一般分为栈内存和堆内存,而在JavaScript中,所谓的栈和堆都是放在堆内存中的,而在堆内存中,JS将其分为栈结构和堆结构去模拟栈内存和堆内存。

上述两种数据类型都会在初始化之后放在堆内存中不同的结构中,可以分为下述两类进行存储:

  • 基本数据类型:存放在栈结构中,引用或者拷贝的时候,会创建一个完全相等的变量;
  • 引用数据类型:存放在堆结构中,存储的是地址,同时会在栈结构中创建一个指针,该指针指向堆结构中存储的地址。多个不同的指针可以指向相同的地址。

数据类型的判断

  • typeof

// 使用typeof有两种方法,分别是1. typeof 变量名 2. typeof(表达式)
function useOnlyTypeOf(item) {
    return typeof item
}

console.log(useOnlyTypeOf(10)) // 'number'
console.log(useOnlyTypeOf(10n)) // 'bigint'
console.log(useOnlyTypeOf('10')) // 'string'
console.log(useOnlyTypeOf(undefined)) // 'undefined'
console.log(useOnlyTypeOf(true)) // 'boolean'
console.log(useOnlyTypeOf(Symbol() )) // 'symbol'
console.log(useOnlyTypeOf([])) // 'object'
console.log(useOnlyTypeOf({})) // 'object'
console.log(useOnlyTypeOf(null)) // 'object'
console.log(useOnlyTypeOf(console)) // 'object'
console.log(useOnlyTypeOf(console.log)) // 'function'

1、对于基本数据类型,除null外,剩余的六种基本数据类型(Number、String、Boolean,Undefined、BigInt、Symbol)都可以准确地进行判断。
2、对于引用数据类型,除了函数(Function)可以准确的判断数据类型外,剩余的全部都会返回’object’。
单独不推荐使用。

  • instanceof

instanceof在使用的过程中需要两个参数,左侧是实例对象(比如为a),右侧是构造函数(比如为Fn),用法为a instanceof Fn,返回布尔值。它主要用与判断左侧的实例对象是否是由右侧的构造函数生成的对象,如果是,则返回true,否则返回false。底层实现逻辑主要是判断右侧构造函数的原型对象是否在左侧实例对象的原型链中。

// instanceof的用法
// BigInt只是函数,没有构造器,因此不能使用new来创建BigInt的实例
// null和undefined都是没有构造函数的
function useOnlyInstanceof(item) {
    if (item instanceof String) {
        return 'string'
    }
    if (item instanceof Number) {
        return 'number'
    }
    if (item instanceof Boolean) {
        return 'boolean'
    }
    if (item instanceof Array) {
        return 'array'
    }
    if (item instanceof Function) {
        return 'function'
    }
     if (item instanceof BigInt) {
        return 'bigint'
    }
    if (item instanceof Object) {
        return 'object'
    }
    // ...等逻辑
    return '无法判断类型'
}
console.log(useOnlyInstanceof('test')) // '无法判断类型'
console.log(useOnlyInstanceof(new String('test'))) // 'string'
console.log(useOnlyInstanceof(10)) // '无法判断类型'
console.log(useOnlyInstanceof(new Number(10))) // number
console.log(useOnlyInstanceof(10n)) // '无法判断类型'
console.log(useOnlyInstanceof(true)) // '无法判断类型'
console.log(useOnlyInstanceof(new Boolean(true))) // 'boolean'
console.log(useOnlyInstanceof([])) // 'array'
console.log(useOnlyInstanceof(console)) // 'object'

// 实现instanceof
function achieveInstanceof(left, right) {
    // 当实例对象为基本数据类型或者null的时候,直接返回false
    if (typeof left !== 'object' || left === null) {
        return false
    }
    let proto = Object.getPrototypeOf(left)
    while(true) {
        if (proto === right.prototype) return true
        if (proto === null) return false
        proto = Object.getPrototypeOf(proto)
    }
}
function Animal() {
}
let cat = new Animal();
let arr = new Array();
console.log(achieveInstanceof(cat, Animal)) // true
console.log(achieveInstanceof(arr, Animal)) // false

instanceof能够准确地判断引用数据类型,但是不能正确的判断基本数据类型。
单独不推荐使用。

  • constructor

constructor作为原型对象的属性,指向构造函数本身。

function useOnlyConstructor(item) {
    return item.constructor.name.toLowerCase();
}

function test() {
    console.log(useOnlyConstructor(arguments))
}

test(); // object
console.log(useOnlyConstructor(document.forms))  // htmlcollection
console.log(useOnlyConstructor(document.querySelectorAll('body'))) // nodelist
console.log(useOnlyConstructor('test')) // string
console.log(useOnlyConstructor(new String('test'))) // string
console.log(useOnlyConstructor(10)) // 'number'
console.log(useOnlyConstructor(new Number(10))) // number
console.log(useOnlyConstructor(10n)) // bigint
console.log(useOnlyConstructor(true)) // boolean
console.log(useOnlyConstructor(new Boolean(true))) // boolean
console.log(useOnlyConstructor([])) // array
console.log(useOnlyConstructor(console)) // object
console.log(useOnlyConstructor(undefined)) //Uncaught TypeError:  Cannot read properties of undefined (reading 'constructor')
console.log(useOnlyConstructor(null)) // Uncaught TypeError: Cannot read properties of null (reading 'constructor')

1、对于基本数据类型,除了null和undefined以外,constructor都可以准确地进行判断。
2、对于引用数据类型,目前的测试情况,除了类数组对象arguments无法准确地判断以外,constructor都可以准确地进行判断。
单独不推荐使用。

  • typeof + constructor + 特殊情况结合使用

// 数据类型判断
function getDataType(item) {
    if (typeof item !== 'object' && item !== null) {
        return typeof item
    }
    if (item === null) {
        return 'null'
    }
    const proto = Object.getPrototypeOf(item);
    return proto.constructor.name.toLowerCase()
}

function test() {
    console.log(getDataType(arguments))
}

test(); // object
console.log(getDataType(document.forms)) // htmlcollection
console.log(getDataType(document.querySelectorAll('body'))) // nodelist
console.log(getDataType(123)) // number
console.log(getDataType('123')) // string
console.log(getDataType(true)) // boolean
console.log(getDataType(Symbol())) // symbol
console.log(getDataType(undefined)) // undefined
console.log(getDataType(null)) // null
console.log(getDataType([])) // array
console.log(getDataType(function() {})) // function
console.log(getDataType({})) // object
console.log(getDataType(new RegExp())) // regexp
console.log(getDataType(new FormData())) // formdata
console.log(getDataType(/123/g)) // regexp
console.log(getDataType(new Date())) // date
console.log(getDataType(new Map())) // map
console.log(getDataType(new Set())) // set
console.log(getDataType(NaN)) //number

// 上述arguments类数组并不符合条件,单独做为条件进行判断
function getDataType(item) {
    if (typeof item !== 'object' && item !== null) {
        return typeof item
    }
    if (item === null) {
        return 'null'
    }
    if (item.callee) {
        return 'arguments'
    }
    const proto = Object.getPrototypeOf(item);
    return proto.constructor.name.toLowerCase()
}

function test() {
    console.log(getDataType(arguments))
}

test(); // arguments

在typeof + constructor + 特殊情况结合使用时,在测试中基本上所有的数据类型都全部满足。
大多数应用场景都可以满足,可以使用。(但不排除有忽略的使用场景模式)

  • Object.prototype.toString

在所有的对象中,都具有一个[[class]]的内部属性,通过Object.prototype.toString.call()方法可以获取到该内部属性,返回的数据格式为[object Xxx],其中Xxx即为对象的类型。

function getType(obj){
  // 先进行typeof判断,如果是基础数据类型,直接返回
  if (typeof obj !== "object") {   
    return typeof obj ;
  }
  // 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); 
}

getType([])     // "Array" 
getType('123')  // "string" 
getType(window) // "Window" 
getType(null)   // "Null"
getType(undefined)   // "undefined" 
getType()            // "undefined"
getType(function(){}) // "function" 
getType(/123/g)      //"RegExp" 

数据类型判断还是Object.prototype.toString方法更靠谱一些。
用就完事了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值