JavaScript 高阶版「检测数据类型方法」

检测数据类型的方法

typeof 底层原理及优缺点

typeof 类型检测

  1. 检测原始值类型
typeof null; 'object'
typeof undefined;'undefined'
typeof 1/-1'number'
typeof NaN'number'
typeof Infinity'number'
typeof true'boolean'
typeof 'guyal''string'
typeof ''; 'string'
typeof Symbol()'symbol'
typeof 10n;'bigint'
  1. 对象类型
typeof {} 'object'
typeof [] 'object'
typeof /^$/ 'object'
  1. 函数
typeof function(){}; 'function'

typeof 底层原理

  • 计算机底层都是通过二进制来进行数据存储的,以不同的数字开头代表不同的数据类型,比如:
    • 1:数字
    • 010:浮点数
    • 100:字符串
    • 110:布尔
    • 000:对象
    • -2^30:undefined
  • JS 设计上的缺陷
    • 凡是以 000 开始的都认为是对象,null 是 000000,所以误认为 null 是 object 类型 「这是 JS 设计的缺陷」

typeof 特点

  • typeof null 的结果是:‘object’
  • typeof 实现 call 的对象,比如:函数,箭头函数、生成器函数、构造函数…,其结果是:‘function’;其余未实现 call 的对象,结果是:‘object’
  • 检测出来的结果是字符串,字符串的内容就是数据对应的类型
  • 检测原始值类型还是比较简单方便的

typeof 缺点

  • 对于对象数据类型,检测出来的结果都是 ‘object’,函数是’function’
  • 因为 typeof 检测是基于构造函数创建出来的,基本数据类型的实例对象,也是一个对象:‘object’,所以使用 typeof 检测出来的对象类型是:object 类型

typeof null 的结果为什么是 object 类型

计算机底层都是根据二进制来存储数据的,以 000 开头的代表对象,而 null 是 000000,计算机误认为是对象,所以,typeof 的检测结果是’object’

instanceof 原理及优缺点

instanceof 用途

  • 主业:检测某个实例是否属于某个类
  • 副业:数据类型检测「可以细分出部分对象的类型」

instanceof 使用范围

  • 基本类型值和 Symbol 类型不能使用「本身不是对象,没有__proto__ 属性」
  • 但是,可以检测基于构造函数创建出来的基本类型对象值

instanceof 底层原理

  • 底层原理:
    • 首先查找 Symbol.hasInstance,如果存在那么就会基于这个属性检测,如果不存在,则基于原型链 proto 查找,只要构造器的 prototype 出现在实例的原型链上,那么结果就为 true;
    • 长话短说:检测当前构造函数的原型 prototype,是否出现在实例的原型链上,如果有,结果就是 true;

instanceof 存在的问题

static [Symbol.hasInstance](实例) {
    return Array.isArray(实例)
}
  • 所有实例的原型链最终都会指向 Object.prototype,所以:实例 instanceof Object 的结果都为 true
  • 在原生 JS 中,原型链都是可以随意改动的,所以,检测出来的结果是不准确的
  • 字面量方式创建的基本数据类型值不能通过 instanceof 方法检测:浏览器不会默认把原始值转换为 new 的方式,所以本身不是对象,不存在__proto__ 属性
  • 不能检测原始值类型

重写 instanceof

Symbol.hasInstance

Object.getPropertyOf


// 重写 instanceof 方法
function my_instanceOf(exam, ctor) {
    let exam_ = typeof exam,
        ctor_ = typeof ctor;
    // 必须保证构造器是一个函数
    if (ctor_ !== 'function' || !ctor.prototype) throw new TypeError(ctor+'is not an constructor') 

    // 排除 null、undefined
    if(exam == null) return false;
    // 排除原始值
    if (!/^(object|function)$/i.test(exam_) ) return false;

    // 条件都可满足
    // 检测是否存在 [Symbol.hasInstance]()
    if (typeof ctor[Symbol.hasInstance] === 'function'){
        return ctor[Symbol.hasInstance](exam)
    }

    // 不存在 [Symbol.hasInstance](),基于原型链机制检测
    let proto = Object.getPrototypeOf(exam);

    while (proto) {
        // 判断 proto 与 ctor.prototype 是否相等
        if(proto === ctor.prototype) return true;
        proto = Object.getPrototypeOf(proto);
    }
    return false;
}
console.log(my_instanceOf([], Array)); //->true
console.log(my_instanceOf([], RegExp)); //->false
console.log(my_instanceOf([], Object)); //->true

Object.prototype.toString.call( [value] )

检测范围

  • Number.prototype
  • String.prototype
  • Symbol.prototype
  • BigInt.prototype
  • Array.prototype
  • RegExp.prototype
  • Function.prototype

返回值

  • 大部分内置类的原型上都有 toString,一般都是转换为字符串,只有 Object.prototype 上的 toString 并不是转换为字符串,而是返回当前实例对象所属类的信息的:’[object 所属类的构造函数信息]’

内置原理

  • 所属类的构造函数信息是根据 Symbol.toStringTag 获取的
  • 有这个属性基于这个获取的,没有则是浏览器自己计算的
  • toString() 找不到 toStringTag 属性时只好返回默认的 Object

Object.prototype.toString.call 是检测数据类型方式的万全之策

constructor

constructor 是可以肆意被修改的,所以也不准,这里就不多说了。
以上内容,如有错误之处,请给予指正!感谢~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值