一、检测数据类型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([要检测的值])