JavaScript如果正确的判断变量类型
前言
javascript是一门弱类型语言,并且制订初期比较粗糙,类型之间也存在很多隐式转换,很多时候我们不需要进行类型判断也能正确地实现我们的逻辑,但准确的判断类型在很多时候可以减少我们的代码错误,然后在类型判断中也存在很多坑。
这次把常用的变量(关键字)等进行实验,看看怎么判断类型检测最好:
// 测试的类型: // string number boolean object array null undefined // regexp date function class window HTMLDomcument Set Symbol const typeList = [ 'string', 1, true, {}, [], null, undefined, new RegExp('\s'), new Date(), function() {}, class Preson {}, window, document.getElementById('app'), new Set(), Symbol() ] 复制代码
方法一:typeof 函数(关键字)
typeof
是javascript提供的最简单的类型判断方法(也是最没用的),可以判断最简单的基础类型,对于对象类型无能为力。
typeof文档
类型检测结果为:
typeList = [ 'string', // string 1, // number true, // boolean {}, // object [], // object null, // object undefined, // undefined new RegExp('\s'), // object new Date(), // object function() {}, // function class Preson {}, // function window, // object document.getElementById('app'), // object new Set(), // object Symbol() //symbol ] typeList.forEach(el => { console.log(el,typeof el) }) 复制代码
显然,typeof
中很多类型都只能推断为object
,只能用于一些基本类型的判断。
方法二:constructor
constructor
是对象的构造函数,本着万事皆对象的原则,理论上一切变量都继承自对象类型(Object),而Object的原型链上有constructor
属性,这个属性表示了创建该变量的构造函数的引用。
Object.prototype.constructor文档
类型检测结果为:
console.log('string'.constructor === String) // true let num = 1 console.log(num.constructor === Number) // true console.log(true.constructor === Boolean) // true console.log({}.constructor === Object) // true console.log([].constructor === Array) // true console.log(null.constructor === null) // 报错:Uncaught TypeError: Cannot read properties of null (reading 'constructor') console.log(undefined.constructor === undefined) // 报错:Uncaught TypeError: Cannot read properties of undefined (reading 'constructor') console.log(new RegExp('\s').constructor === RegExp) // true console.log(new Date().constructor === Date) // true console.log((function() {}).constructor === Function) // true console.log((class Preson {}).constructor === Function) // true class Preson {} console.log(new Preson().constructor === Preson) // true console.log(window.constructor === Window) // true console.log(document.getElementById('app').constructor === HTMLDivElement) // true console.log(new Set().constructor === Set) // true console.log(Symbol().constructor === Symbol) // true 复制代码
因为是属性调用,所以null
和undefined
是无法使用该方法的,且constructor
打印出来并不方便观察,所以一般只能用在判断是否等于某一种变量时使用,比如 [].constructor === Array
需要注意的是,constructor
是可以被修改的。
方法三:instanceof
instanceof
和constructor
有些类似:
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
看定义有点绕,举例子说明会好理解些:[] instanceof Array
,Array(构造函数)的prototype
是否出现在[]的原型链上?
很显然,[]是个数组,它的原型链上一定能找到Array对象以及Array的prototype
。
instanceof文档
类型检测结果为:
console.log('string' instanceof String) // false let num = 1 console.log(num instanceof Number) // false console.log(true instanceof Boolean) // false console.log({} instanceof Object) // true console.log([] instanceof Array) // true console.log(null instanceof null) // 报错 console.log(undefined instanceof undefined) // 报错 console.log(new RegExp('\s') instanceof RegExp) // true console.log(new Date() instanceof Date) // true console.log((function() {}) instanceof Function) // true console.log((class Preson {}) instanceof Function) // true class Preson {} console.log(new Preson() instanceof Preson) // true console.log(window instanceof Window) // true console.log(document.getElementById('app') instanceof HTMLDivElement) // true console.log(document.getElementById('app') instanceof HTMLElement) // true console.log(new Set() instanceof Set) // true console.log(Symbol() instanceof Symbol) // false 复制代码
非引用类型无法通过instanceof
来判断类型,同样null
和undefined
这两个特殊的类型使用instanceof
也会报错。
还有两个比较特别的:
Symbol
作为一种特别的类型,打印s.prototype
为undefined
,所以也无法通过instanceof
来判断类型。dom节点,
HTMLDivElement
和HTMLElement
都在原型链上,因为HTMLDivElement
和HTMLElement
实际上也是继承关系,所以在原型链接上都存在,同样道理,万物皆对象,以下判断都为true
[] instanceof Object // true {} instanceof Object // true 复制代码
所以在判断一个变量是数组还是对象时,一定是判断 instanceof Array
,而不是 instanceof Object
。
方法四:Object.prototype.toString.call
万物皆对象,在这个例子中体现的淋漓尽致,使用这个方法基本上可以区分所有类型:
类型检测结果为:
const typeList = [ 'string', // [object String] 1, // [object Number] true, // [object Boolean] {}, // [object Object] [], // [object Array] null, // [object Null] undefined, // [object Undefined] new RegExp('\s'), // [object RegExp] new Date(), // [object Date] function() {}, // [object Function] class Preson {}, // [object Function] window, // [object Window] document.getElementById('app'), // [object HTMLDivElement] new Set(), // [object Set] Symbol() // [object Symbol] ] typeList.forEach(el => { console.log(el,Object.prototype.toString.call(el)) }) 复制代码
前面几种方法的问题几乎都不再存在,唯一的缺点就是打印结果有点难看,但是好在很标准,所以我们可以通过简单的函数封装,让类型判断更简单一些。
判断类型的方法封装:
function type(val) { const type = Object.prototype.toString.call(val) return type.slice(type.indexOf(" ") + 1,type.length - 1).toLocaleLowerCase() }
作者:蓝德锦
链接:https://juejin.cn/post/7171233789660626951
来源:https://www.77cxw.com/