开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
前言
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提供的最简单的类型判断方法(也是最没用的),可以判断最简单的基础类型,对于对象类型无能为力。
类型检测结果为:
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
。
类型检测结果为:
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()
}