类型判断
前言
在 web 开发和前端工具类库中,我们能够看到类型判断的广泛应用。
类型判断,顾名思义就是判断一个值是简单类型还是复杂类型。接下来让我们来学习下如何在代码中实现类型判断。
typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
我们知道在 ES6 之前,JavaScript 有 6 种数据类型,分别是:Undefined、Null、Boolean、Number、String、Object。通过下面例子,观察下它们被判断成什么结果。
console.log(typeof bar) // undefined
console.log(typeof null) // object
console.log(typeof true) // boolean
console.log(typeof 42) // number
console.log(typeof 'foo') // string
console.log(typeof {}) // object
console.log(typeof function baz() {}) // function
我们发现这上面有两个特殊的地方,一个是 null 被判断成是 Object 类型,另一个是 function 类型,它不在 6 种数据类型内。虽然 typeof 可以检测出 JavaScript 的六种数据类型,但是 Object 下还有很多细分的类型,如 Array、Function、Date、RegExp、Error 等。
举个例子看下检测情况:
console.log(typeof new Date()) // object
console.log(typeof new Array()) // object
咦?Object 的细分类型该怎么区分呢?答案是 Object.prototype.toString。
Object.prototype.toString
toString() 方法返回一个表示该对象的字符串。
每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中 type 是对象的类型。
我们使用 toString()
方法查看上面的 Date 和 Array 的类型:
const date = new Date()
const array = new Array()
console.log(Object.prototype.toString.call(date)) // [object Date]
console.log(Object.prototype.toString.call(array)) // [object Array]
因此我们可以使用 toString()
方法来区分 Object 的细分类型。
typeof 虽然不能区分 object 的细分类型,但是它的性能比较好。具体见下面的测试结果图:
测试网站戳这里哈~
isString
我们跟着 lodash 库学习下如何实现字符串检测,下面贴出相关源码:
const toString = Object.prototype.toString
function getTag (value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
}
function isString (value) {
const type = typeof value
return type === 'string' ||
(type === 'object' && value != null && !Array.isArray(value) && getTag(value) == '[object String]')
}
// demo
const a = new String('hello')
const b = 'world'
console.log(isString(a)) // true
console.log(isString(b)) // true
分析:从源码可以得出,lodash 为了追求性能首先是使用 typeof
操作符进行检测,如果这一步不能判断出具体类型,再使用 Object.prototype.toString()
方法进行检测。
这里可能有同学产生疑问,咦?为什么源码中出现了 !Array.isArray(value)
这个条件判断?本人推测是性能方面的考虑。因为 Array.isArray()
的运行性能比 Object.prototype.toString()
优,所以避免使用 Object.prototype.toString
判断不是 string 类型的值。
isObject
我们跟着 lodash 库学习下如何实现对象检测,下面贴出相关源码:
function isObject (value) {
const type = typeof value
return value != null && (type === 'object' || type === 'function')
}
分析:首先排除了 null 这个值,因为上面提过它的 typeof 检测值是 object,然后就是不要漏了函数类型,因为函数是对象的细分类,而它的 typeof 检测值是 function,最后返回判断结果值。
结语
本文到这里就结束了。在 lodash 库里还有其它类型检测的方法,感兴趣的同学可以去阅读源码,类型判断的大体思路是我上面介绍的 typeof
和 Object.prototype.toString
方法。