2020前端面试复习-js部分-数据类型检测

95 阅读3分钟

数据类型检测

  1. typeof:检测数据类型的运算符
    1. 返回结果是一个字符串,字符串中包含了对应的数据类型(number、string、boolean、undefined、symbol、bigint、object)typeof typeof xxx 结果都是’string‘
    2. 小bug:typeof null =》 object typeof按照计算机底层存储的二进制结果进行检测,object是以000开始的,null的二进制存储时000,所以会是别成object
    3. 所有对象都是以000开始的,所以基于typeof检测的结果都是object,也就是typeof无法细分是普通对象还是数组等对象
  2. instanceof
    1. 并不是用开检测数据类型的,是用来检测当前实例是否属于这个类
    2. 一般指应用于普通对象、数组对象、正则对象、日期对象等的具体细分
    3. 绝对不能证明instanceof Object为true就是普通对象
    let arr = [];
    console.log(arr instanceof Array) //true
    console.log(arr instanceof Object) //true
    console.log(arr instanceof RegExp) //true
    
    1. instanceof无法应用到原始值类型数值的检测上
    let n = 10;
    let m = new Number(10);
    console.log(n.toFixed(2));//10.00 n是number的实例,只不过她是字面量方式创造出来的原始类型值(其实n.toFixed(2)的时候,n这个节本类型值浏览器也会Object(n),然后再调用方法,因为此时具备了__proto__)
    console.log(m.toFixed(2));//10.00 m是number的实例,只不过她是构造函数方式创造出来的引用类型值
    console.log(n instanceof Number)//false
    console.log(m instanceof Number)//true
    
    function Person(){}
    Person.prototype=Array.prototype;
    let p1 = new Person;
    console.log(p1);
    //虽然p1可以基于__proto__找到Array.prototype,但是它不具备数字的任何特征(length、索引都没有),所以断定这个一定不是一个数组
    console.log(p1 instanceof Array)//true
    
    1. 基于‘实例 instanceof 类’检测是时候,浏览器底层是这样处理的 ‘类Symbol.hasInstance
      1. Function.prototype[Symbol.hasInstance]=function Symbol.hasInstance{native code} 只有函数function.prototype上有这个方法
      2. Symbol.hasInstance方法执行原理
        1. 根据当前实例的原型链上(proto)是否存在这个类的原型(prototype)
        2. arr.proto===Array.prototype =>arr.instanceof Array=>true
        3. arr.proto.proto===Object.prototype =>arr.instanceof Object=>true
    let arr = [];
    console.log(arr.instanceof Array); //true
    console.log(arr.instanceof Object); //true
    console.log(Array[Symbol.hasInstance](arr))//true 
    
    let obj = {};
    console.log(arr instanceof obj)//报错
    //因为obj是一个对象,没有[symbol.hasInstance]这个属性(函数才可以调用Function.prototype上的这个方法
    
  3. constructor
    1. 原本就是获取市里的构造函数的,基于这些特点可以充当数据类型检测
    2. 比instanceof好用
    3. 但是也不准确:constructor是可以随意被修改的
    let arr = [];
    console.log(arr.constructor === Array); //true
    //在constructor不被修改的情况下,这样区分是数组还是普通对象
    console.log(arr.constructor === Object); //false
    console.log(arr.constructor === RegExp)//false 
    
    function Person(){}
    Person.prototype=Array.prototype;
    let p1 = new Person;
    console.log(p1.constructor === Array);//true
    //一旦原型重定向,constructor也改了,所以不准确
    
    let n = 10;
    let m = new Number(10);
    console.log(n.constructor===Number)//true
    console.log(m.constructor=== Number)//true
    
  4. Object.prototype.toString.call(value)或者({}).toString.call([value])
    1. 专门用来检测数据类型的,基本零瑕疵
    2. number/string/boolean/symbol/bigint/function/array/object...的原型上都有toString,除了Object.prototype.toString不是转换字符串的,其余都是,Object.prototype.toString说是用来检测数据类型的
    3. 返回结果‘[object 对象[Symbol.toStringTag]||对象的构造函数(不受自己修改的影响,对内置类有效))||Object]’
    let class2type = {},
    toString = class2type.toString;//Object.prototype.toString
    
        class Person {
            get[Symbol.toStringTag](){
                return "Person";
            }
        }
        let p1 = new Person;
        toString.call(p1)=> '[object Person]'
    

    重写instanceof

    1. obj-要检测的实例对象(不支持原始值类型)
    2. constructor-要检测类,必须是一个函数
    function instance_of(obj,constructor) {
        if(obj====null ||typeof obj!==(function||function)) return false;
        if (typeof constructor !== 'function') throw new TypeError;
        let proto = obj.__proto__,
            prototype = constructor.prototype;
            while(true){
                if(proto === null) return false;
                //找到Object.prototype.__proto__doumeiyouxiangdengde,则证明不是当前累的实例
                if(proto===prototype) return true;
                //找到对象的原型链包含类的原型,则证明对象是类的一个实例
                proto = proto.__proto__;
                //一级级查找
            }
    
    }