数据类型检测
1. typeof
typeof 是直接在计算机底层基于数据类型的二进制值来检测类型的。
对于原始类型,除了 null 类型,其他都能显示正确的类型。
对于 null 作为基本数据类型为什么会返回 object 是一个历史遗留Bug,在JS中,数据类型二进制前三位为 000 会被判断为 object 类型,而 null 底层的二进制为全0,故前三位肯定也是 000,所以被判断为 object 。
对于对象(普通对象/数组对象/正则对象/日期对象)类型,除了函数都会显示 object 类型,所以 typeof 并不能很精确判断的对象类型的数据。
typeof [] // "object"
typeof {} // "object"
typeof console.log // "function"
2. instanceof
instanceof 初始被设计出来是用来检测某一个实例是否属于某一个类的,后续引申出用来检测数据类型,所以也并不能判断所有的数据类型(不能检测基本类型。
如果我们想判断一个 对象 的正确类型,这时候可以考虑使用 instanceof,因为内部机制是通过原型链来判断的,只要当前类出现实例的原型链上,结果就为 true 。
由于我们可以修改原型的指向,所以检测出来的结果不一定准确。
了解了 instanceof 的机制,在后面的章节中我们也会自己去实现一个 instanceof。
function instanceOf(example, classFunc) {
let classFuncPrototype = classFunc.prototype,
proto = Object.getPrototypeOf(example)
while (true) {
if (!proto) {
// Object.prototype.__proto__ 为 null
return false
}
if (proto === classFuncPrototype) {
return true
}
proto = Object.getPrototypeOf(proto)
}
}
3. constructor
可以通过 constructor 来判断数据的类型,但是除了null和undefined,因为他们不是由对象构建。
需要注意,如果改变类的 constructor, constructor 就不能用来判断数据类型了。
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
4. Object.prototype.toString.call()
检测数据类型的最标准的方法。
Object.prototype.toString() 方法不是转换为字符串,而是返回当前实例所属类的信息。故让 Object.prototype.toString() 指向,并把 this 指向为要检测的值,就能返回当前值所属类的信息。
5. JQ封装的类型检测方法
var class2type = {}
var toString = class2type.toString // Object.prototype.toString
["Boolean", "Number", "String", "Function", "Array", "Date",
"RegExp", "Object", "Error", "Symbol"].forEach(name => {
class2type[`[object ${name}]`] = name.toLowerCase()
})
function toType() {
if (obj == null) {
return obj + ""
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || 'object' :
typeof obj
}