在日常的开发过程中,我们经常需要验证某个变量或参数所代表的数据的类型,以保证程序仅处理类型相符的数据,避免错误。
自 ES6 发布之后,JavaScript 中的数据类型又多了几种,但判断的方式基本还是一样的。
这篇文章就来温习一下 JavaScript 中判断数据类型的方式。
数据类型
JavaScript 中的数据类型分为两类,一类是原始类型,包括 String
、Number
、Boolean
、Null
、Undefined
、Symbol
和 BigInt
;另一类是引用类型,包括:Array
、Map
、Set
、WeakMap
、WeakSet
、JSON
、RegExp
、Date
、Function
和 Object
。
判断方法
JavaScript 中常见的判断数据类型的方法有四种(个人认为两种有效的只有两种),它们各有优缺点。
typeof
typeof
在判断数据类型时,会以全小写字符串的形式返回判断结果,如下:
console.log(typeof 'qingcong') // string
console.log(typeof 123) // number
console.log(typeof true) // boolean
console.log(typeof null) // object
console.log(typeof undefined) // undefined
console.log(typeof Symbol('x')) // symbol
console.log(typeof BigInt(100)) // bigint
console.log(typeof []) // object
console.log(typeof new Map()) // object
console.log(typeof new WeakMap()) // object
console.log(typeof new Set()) // object
console.log(typeof new WeakSet()) // object
console.log(typeof new RegExp(/\d/)) // object
console.log(typeof new Date()) // object
console.log(typeof new Function()) // function
console.log(typeof new Object({})) // object
可以看到,对于原始类型,除了 null
返回的是 object
外,其余判断都是正确的;而对于引用类型来说,除了 Function
判断正确外,其余的都返回了 object
。
因此,typeof
可以用来判断原始类型和 Function
,但对于其它引用类型的数据 typeof
无能为力。
instanceof
由于 typeof
的限制性,JavaScript 中还提供了 instanceof
操作符,但严格来说,instanceof
并不是一种判断数据类型的方法,它检测的是构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
例如:
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
function Plane(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
let myCar = new Car("Honda", "Accord", 1998);
console.log(myCar instanceof Car); // true
console.log(myCar instanceof Plane); // false
不过也正是因为原型链的缘故,instanceof
在判断时会出现偏差,例如:
console.log(myCar instanceof Object); //true
因为 Object
也在 myCar
的原型链上。
如果修改了实例对象的原型,那么结果也会不一样:
Object.setPrototypeOf(myCar, Plane.prototype);
console.log(myCar instanceof Car); // false
console.log(myCar instanceof Plane); // true
同时,因为是检测实例对象的原型链,所以下面的这两种形式都是无效的:
let stringA = "A simple string";
let stringB = String("A string made with constructor");
console.log(stringA instanceof String) // false
console.log(stringB instanceof String) // false
console.log(stringA instanceof Object) // false
console.log(stringB instanceof Object) // false
必须是通过 new
创建的实例对象才可以:
let stringC = new String("A string made with new");
console.log(stringC instanceof String) // true
console.log(stringC instanceof Object) // true
查看三者的结构,就会发现区别:
使用 typeof
检测可以得出:
console.log(typeof stringA) // string
console.log(typeof stringB) // string
console.log(typeof stringC) // object
这就是本节开头所说的,instanceof
并不是一种判断数据类型的方法的原因。
constructor
此方法是通过判断对象的构造器来判断其数据类型的,它并不是由 JavaScript 直接提供的一种判断方法,而是一种变通的方法,本质上和 instanceof
的判断方式是相同的,也是以原型链的形式进行。
所以,instanceof
方法的缺点它都有,这里就不展开了。
toString
toString
方法是 Object
的原型方法,也是一种判断数据类型的变通方法,它会返回一个 [object xxxx]
的形式的字符串,其中 xxxx
就是对象的类型。
例如:
console.log(Object.prototype.toString.call("qingcong")); // [object String]
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(Symbol("x"))); // [object Symbol]
console.log(Object.prototype.toString.call(BigInt(100))); // [object BigInt]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(new Map())); // [object Map]
console.log(Object.prototype.toString.call(new WeakMap())); // [object WeakMap]
console.log(Object.prototype.toString.call(new WeakSet())); // [object WeakSet]
console.log(Object.prototype.toString.call(new RegExp(/\d/))); // [object RegExp]
console.log(Object.prototype.toString.call(new Date())); // [object Date]
console.log(Object.prototype.toString.call(new Function())); // [object Function]
console.log(Object.prototype.toString.call(new Object())); // [object Object]
可以看到,此方法的判断非常准确。
结语
尽管在日常开发中,我们并不会真的需要判断每一种数据类型,但判断的方法是通用的,掌握了方法,就能从容应对各种需求。
还有一点要说的是,ES6 提供了一个 Array.isArray()
方法专门用于检测某个变量是否是数组类型,在日常开发中也可以使用。