JS中檢測數據類型的方案

一、檢測數據類型1:typeof
返回結果都是字符串
字符串中包含了對應的數據類型:“number”/“string”/“boolean”/“undefined”/“symbol”/“object”/“function”
【侷限性】
typeof null = “object”, null是空對象指針(在代碼中會提現用法)
檢測數組或者正則等特殊的對象,返回結果都是"object",所以無法基於typeof判斷是數據還是正則

<script>
        let obj = {}; //=> obj的值等於一個堆內存,稱爲AAAFFF000,若這個堆內存在其他位置被佔用,不能銷燬,但是若想銷燬的時候就直接給obj賦值爲null,讓obj不再指向任何堆內存,obj=null,在瀏覽器空閒的時候,就會銷燬這個沒有被佔用的堆內存(谷歌瀏覽器就是隨時檢測在空閒的時候看哪些堆內存沒有被佔用,就會釋放這個堆內存;IE瀏覽器不同,堆內存被一個變量佔用計數爲1,被兩個變量佔用計數爲2,若把其中一個賦值爲null,計數直接減1)
        console.log(12); //number
        console.log(typeof []); //=> "object"
        console.log(typeof typeof []); //=>“string” 無論前面多少typeof,返回結果都是"string"
    </script>

二 / 三、檢測數據類型2/3:instanceof/constructor
檢測某個實例是否屬於這個類
它檢測的底層機制:所有出現在其原型鏈上的類,檢測結果都是TRUE,
【侷限性】:
由於可以基於__proto__或者prototype改動原型鏈的動向,所以基於instanceof檢測出來的結果並不一定是準確的。
基本數據類型的值,連對象都不是,更沒有__proto__。雖說也是所屬類的實例,在JS中也可以調取所屬類原型上的方法,但是instanceof是不認得

<script>
        // console.log(12 instanceof Number); //=>false
        // console.log(new Number(12) instanceof Number); //=>true
        // console.log([] instanceof Array); //=>true
        // console.log([] instanceof Object); //=>true

        function Fn() { };
        Fn.prototype.__proto__ = Array.prototype;
        let f = new Fn();
        //原型鏈:f -> Fn.prototype -> Array.prototype -> Object.prototype
        console.log(f instanceof Array); //true,f不是數組,不滿足數組的結構,因上面一行的作用,可以調用數組原型上的方法,因爲原型鏈指向可以隨意改動,所以instanceof出來的結果不一定是準確的。 
        let arr = [];
        Array.prototype.constructor = null;
        // console.log(arr.constructor === Array); false ,與instanceof一樣,constructor是可以隨意修改的,當prototype改變時,constructor也會改變,值是不準確的
        //基本數據類型也可以用constructor判斷
        console.log(arr.constructor); //null
        console.log((12).constructor === Number); //true

四、檢測數據類型4:Object.prototype.toString.call([value])/({}).toString.call([value])
不是用來轉換爲字符串的,而是返回當前實例所屬類的信息
格式:"[object 所屬類的信息]"
“[object Object/Array/RegExp/Date/Function/Null/Undefined/Number/String/Boolean/Symbol…]”
這種方式基本上沒有什麼侷限性,是檢測數據類型最準確的方式

<script>
        //可以直接f12在控制檯中輸入Number/String/Boolean/Symbol/Array等.prototype查看他們的原型,會顯示如以下信息
        /*
        Number.prototype
        Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}constructor: ƒ Number()toExponential: ƒ toExponential()toFixed: ƒ toFixed()toPrecision: ƒ toPrecision()toString: ƒ toString()valueOf: ƒ valueOf()toLocaleString: ƒ toLocaleString()__proto__: Object[[PrimitiveValue]]: 0
        String.prototype
        String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}length: 0constructor: ƒ String()anchor: ƒ anchor()big: ƒ big()blink: ƒ blink()bold: ƒ bold()charAt: ƒ charAt()charCodeAt: ƒ charCodeAt()codePointAt: ƒ codePointAt()concat: ƒ concat()endsWith: ƒ endsWith()fontcolor: ƒ fontcolor()fontsize: ƒ fontsize()fixed: ƒ fixed()includes: ƒ includes()indexOf: ƒ indexOf()italics: ƒ italics()lastIndexOf: ƒ lastIndexOf()link: ƒ link()localeCompare: ƒ localeCompare()match: ƒ match()matchAll: ƒ matchAll()normalize: ƒ normalize()padEnd: ƒ padEnd()padStart: ƒ padStart()repeat: ƒ repeat()replace: ƒ replace()search: ƒ search()slice: ƒ slice()small: ƒ small()split: ƒ split()strike: ƒ strike()sub: ƒ sub()substr: ƒ substr()substring: ƒ substring()sup: ƒ sup()startsWith: ƒ startsWith()toString: ƒ toString()trim: ƒ trim()trimStart: ƒ trimStart()trimLeft: ƒ trimStart()trimEnd: ƒ trimEnd()trimRight: ƒ trimEnd()toLocaleLowerCase: ƒ toLocaleLowerCase()toLocaleUpperCase: ƒ toLocaleUpperCase()toLowerCase: ƒ toLowerCase()toUpperCase: ƒ toUpperCase()valueOf: ƒ valueOf()Symbol(Symbol.iterator): ƒ [Symbol.iterator]()__proto__: Object[[PrimitiveValue]]: ""
        Boolean.prototype
        Boolean {false, constructor: ƒ, toString: ƒ, valueOf: ƒ}constructor: ƒ Boolean()toString: ƒ toString()valueOf: ƒ valueOf()__proto__: Object[[PrimitiveValue]]: false
        Symbol.prototype
        Symbol {Symbol(Symbol.toStringTag): "Symbol", constructor: ƒ, toString: ƒ, valueOf: ƒ, …}description: (...)constructor: ƒ Symbol()toString: ƒ toString()valueOf: ƒ valueOf()Symbol(Symbol.toStringTag): "Symbol"Symbol(Symbol.toPrimitive): ƒ [Symbol.toPrimitive]()get description: ƒ description()__proto__: Object
        Function.prototype
        ƒ () { [native code] }
        dir(Function.prototype)
        VM688:1 ƒ anonymous()arguments: (...)caller: (...)length: 0name: ""constructor: ƒ Function()apply: ƒ apply()bind: ƒ bind()call: ƒ call()toString: ƒ toString()Symbol(Symbol.hasInstance): ƒ [Symbol.hasInstance]()get arguments: ƒ ()set arguments: ƒ ()get caller: ƒ ()set caller: ƒ ()__proto__: Object[[FunctionLocation]]: <unknown>[[Scopes]]: Scopes[0]
        Array.prototype
        [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]length: 0constructor: ƒ Array()concat: ƒ concat()copyWithin: ƒ copyWithin()fill: ƒ fill()find: ƒ find()findIndex: ƒ findIndex()lastIndexOf: ƒ lastIndexOf()pop: ƒ pop()push: ƒ push()reverse: ƒ reverse()shift: ƒ shift()unshift: ƒ unshift()slice: ƒ slice()sort: ƒ sort()splice: ƒ splice()includes: ƒ includes()indexOf: ƒ indexOf()join: ƒ join()keys: ƒ keys()entries: ƒ entries()values: ƒ values()forEach: ƒ forEach()filter: ƒ filter()flat: ƒ flat()flatMap: ƒ flatMap()map: ƒ map()every: ƒ every()some: ƒ some()reduce: ƒ reduce()reduceRight: ƒ reduceRight()toLocaleString: ƒ toLocaleString()toString: ƒ toString()Symbol(Symbol.iterator): ƒ values()Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …}__proto__: Object
        RegExp.prototype
        {constructor: ƒ, exec: ƒ, …}dotAll: (...)flags: (...)global: (...)ignoreCase: (...)multiline: (...)source: (...)sticky: (...)unicode: (...)constructor: ƒ RegExp()exec: ƒ exec()compile: ƒ compile()toString: ƒ toString()test: ƒ test()Symbol(Symbol.match): ƒ [Symbol.match]()Symbol(Symbol.matchAll): ƒ [Symbol.matchAll]()Symbol(Symbol.replace): ƒ [Symbol.replace]()Symbol(Symbol.search): ƒ [Symbol.search]()Symbol(Symbol.split): ƒ [Symbol.split]()get dotAll: ƒ dotAll()get flags: ƒ flags()get global: ƒ global()get ignoreCase: ƒ ignoreCase()get multiline: ƒ multiline()get source: ƒ source()get sticky: ƒ sticky()get unicode: ƒ unicode()__proto__: Object
        */
        //Number/String/Boolean/symbol 他們的原型上都有:
        //  =>toString:轉化爲字符串
        //  =>valueOf:返回原始值(都是基本類型的值)
        //Array/RegExp/Function等內置類的原型上都有:
        //  =>toString:轉化爲字符串
        // Object的原型上:
        //  =>toString:返回當前實例所屬類的信息
        //  =>valueOf:返回原始值(都是基本類型的值)

        //  Object.prototype.toString.call([]); //容易理解的寫法
        // let obj = {}; obj.toString(); //=>結果"[object Object]" 不直接寫Object.prototype.toString也可以,但是調用的依舊是Object原型上的toString方法 
        // ({}).toString(); //=>"[object Object]" 也可以直接這麼寫,簡便易懂的寫法
        /*
         具體使用,可以直接在控制檯中輸入:
            ({}).toString.call(12)  => "[object Number]"
            ({}).toString.call('12')  => "[object String]"
            ({}).toString.call(true)  => "[object Boolean]"
            ({}).toString.call(null)  => "[object Null]"
            ({}).toString.call(undefined)  => "[object Undefined]"
            ({}).toString.call(Symbol())  => "[object Symbol]"
            ({}).toString.call([])  => "[object Array]"
            ({}).toString.call(/^$/)  => "[object RegExp]"
            ({}).toString.call(function(){})  => "[object Function]"
        */
        // 也可以直接控制檯輸出,以檢驗這種方法是否可行
        console.log(({}).toString.call(12)); //[object Number]
        console.log(({}).toString.call([])); //[object Array]
        console.log(({}).toString.call(Symbol())); //[object Symbol]
        console.log(({}).toString.call(/^$/)); //[object RegExp]
    </script>

以上就是四種檢測數據類型的方法,總結:
對於基本數據類型,一般都是使用typeof就可以搞定,比較簡單
而對於引用類型的,比如想檢測是否是數組,若不嚴謹的情況下instanceof就可以,若要嚴謹就要使用Object.prototype.toString.call([要檢測的值])

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章