原文地址
掘金
求 star
思维导图
JS 中的类型
- 基本类型,
number,string,null,undefined,Boolean
,es6 新增的symbol
,es11
中的bigint
总共 7 种基本类型 引用类型:
object,function
。数据类型的检测方式
数据类型的检测的方法中共有四种
typeof, instanceof, Object.prototype.toString.call(), constructor
一、typeof
typeof 检测原理是:在计算机底层 根据js数据类型的二进制的值进行检测的
。
typeof
检测类型后的返回值是一个字符串
,ES5 中对于一个为定义的变量判断类型也会抛出字符串undefined
,而不是报错。但是用let, const
声明的变量也能会导致暂时性死区,抛出ReferenceError
。typeof undefined //"undefined" typeof a // "undefined" typeof b // "ReferenceError" let b typeof 12 //"number" typeof NaN //"number" typeof '' //"string" typeof 1n //"bigint" typeof function(){} //"function"
- (缺点)
typeof
可以检测除了null
类型以外的数据型。null
被检测成object
这是一个历史遗留的 bug。 - (缺点)
typeof
不能检测出具体的object
类型,因为对象类型的二进制开头都是 000。比如typeof [] //"object"
检测数组,正则,日期等。 - 其他类型的二进制,
000
对象,00000...
null,1
整数,010
浮点数 ,100
字符串,110
布尔值 ,-2^30
undefined
typeof {} // "object"
typeof [] // "object"
typeof /^/ // "object"
typeOf 判断函数为什么可以判断出是 function 类型而不是 object
JS 中虽然函数也是对象,但是typeOf
判断函数是会调用call
方法来判断。所以能判断出function
思考:typeof null 检测出来的结果为什么是 object
typeof
是根据二进制值来判断数据类型的,null
的二进制值是 000,而object
类型的二进制值都是 000 开头的,所以typeof
检测null
是也被检测成object
,这是一个历史里留下来的bug
思考:0.1 + 0.2 !== 0.3 成立原因
二、滥竽充数的 instanceof
instanceof
检测机制是:判断右侧的类型是否出现在左侧实例的原型链上,出现了返回的结果就是true 否则是 false
。
instanceof
判断返回的结果是一个 Boolean 值。instanceof
是用来检测当前的实例是否属于某个类的。可以用来解决typeof
无法检测具体的对象类型的问题。let ary = [] console.log(ary instanceof Array) // true let reg = /^/ console.log(reg instanceof RegExp) // true
- (缺点) 只要当前类出现在实例的原型链上检测的结果就是
true
,那么Object
类型检测的结果永远都是true
,如果实例的原型被修改了,即使检测的结果是true
,也是不准确的。 (缺点)
instanceof
不能检测基本数据类型。// 出现在原型链上的类型都被判断成true let ary = [] console.log(ary instanceof Object) // true function fn(){} fn.prototype = Array.prototype // 原型被修改了 let f = new fn() console.log(f instanceof Array) // true console.log(f instanceof Function) // false // 不能检测基本数组类型 console.log(1 instanceof Number) //false console.log('' instanceof String) //false console.log(false instanceof Boolean) //false
思考,模拟实现 instanceof
思路:根据左侧实例的原型链上是否出现右侧的类型进行判断结果。即
实例.__proto__ === 类.prototype
,则是true 否则是 false。对原型和原型链不熟悉的可以看 面试 | 你不得不懂得 JS 原型和原型链。function _instanceof(example, classP) { let proto = Object.getPrototypeOf(example), classPrototype = classP.prototype while (true) { if (proto === classPrototype) { return true } if (proto === null) { return false } proto = Object.getPrototypeOf(proto) } _instanceof([], Array) //true _instanceof('', Array) // false _instanceof('', Object) // true
三、滥竽充数的 constructor
instanceof
检测机制是:constructor
存放的就是构造函数本身,通过存放的构造函数来检测类型。不熟悉constructor
的也可以看 面试 | 你不得不懂得 JS 原型和原型链。
constructor
可以检测基本类型,这点比instanceof
好用let ary = [] ary.constructor === Array // true,ary.constructor ==> Array.prototype.constructor ary.constructor === String // false ary.constructor === Object // false let a = 1 a.constructor === Number // true let s = '' s.constructor === String // true
(缺点)
constructor
和instanceof
有一样的缺陷,就是constructor
可以被修改也就是重定向Number.prototype.constructor = 'abc' let a = 1 a.constructor === Number // false
四、Object.prototype.toString.call(),标准检测类型
检测机制是:利用Object.prototype.toString
返回实例所属类的信息,通过改变toString
中的this
指向来返回指定参数的类型。
Object.prototype.toString
返回的格式固定是'[object xxx]'
,可以检测任意类型Object.prototype.toString.call(1) //"[object Number]" Object.prototype.toString.call('') //"[object String]" Object.prototype.toString.call(null) //"[object Null]" Object.prototype.toString.call(undefined) //"[object Undefined]" Object.prototype.toString.call(Symbol()) //"[object Symbol]" Object.prototype.toString.call([]) //"[object Array]" Object.prototype.toString.call(function(){}) //"[object Function]" Object.prototype.toString.call({}) //"[object Object]"
- (缺点) 不能直接提取出数据类型,还需要转变才拿到直接的类型
五、其他快捷判断方式
isNumber()
,isNaN()
,Array.isArray()
。。。
六、封装一个万能的检测方法 toType()
1. jQuery 中的类型检测
(function () {
// jquery 中的 toType
let class2type = {},
toString = class2type.toString
// 设定类型映射表
let arrType = ['Number', 'String', 'Boolean', 'Symbol', 'Array', 'Date', 'Error', 'RegExp', 'Function', 'Object']
arrType.forEach(item => {
class2type[`[object ${item}]`] = item.toLowerCase()
});
function toType(checkType) {
if (checkType === null || checkType == undefined) {
return checkType + ''
}
return typeof checkType == 'object' || typeof checkType == 'function' ? class2type[toString.call(checkType)] : typeof checkType
}
window.toType = toType
})()
toType(1) //"number"
toType('') //"string"
toType(null) //"null"
toType(undefined) //"undefined"
toType({}) //"object"
toType(function(){}) //"function"
toType([]) //"array"
本质上还是利用了Object.prototype.toString.call()
2. 自封装一个更简单的 selfType()
(function () {
function selfType(checkType) {
let res = {}.toString.call(checkType).split(' ')[1].split(']')[0].toLowerCase() // 可以使用正则
return res
}
window.selfType = selfType
})()
selfType('') //"string"
selfType(1) //"number"
selfType(null) //"null"
selfType(undefined) //"undefined"
selfType(function(){}) //"function"
selfType({}) //"object"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。