JS数据类型及判断&typeof和instanceof的区别
数据类型
JS 数据类型分为两大类:
1、原始数据类型:String
、Number
、Boolean
、Undefined
、Null
、Symbol
(es6 新增,表示独一无二的值)、Bigint
(es10 新增)
2、引用类型:Object
其中 Object
中又包含了很多子类型(通过原型链继承),比如 Array
、Date
、Function
、Math
、Map
、Set
、Regexp
等等,总之除了原始数据类型皆为引用类型。
存储方式
原始数据类型:直接存储在栈(stack)中,占据空间小、大小固定,属于被频繁使用数据
引用数据类型:同时存储在栈(stack)和堆(heap)中,占据空间大、大小不固定。引用数据类型在栈中存储指针,指向堆中存的实体的地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
ps:这样设计的原因在于
原始类型因为占据空间是固定的,可以将他们存在较小的内存中-栈中,这样便于迅速查询变量的值。引用数据类型大小不固定且会变化,固然不能直接放在栈中,但是其地址是固定的,可以将地址存在栈中。
类型判断
类型判断有以下几种方式
typeof
instanceof
constructor
Object.prototype.toString.call()
typeof
原始类型中除了null
会判断成Object,其它类型都可以通过 typeof 来判断
引用类型除了 函数
都会显示 Object
1 | console.log(typeof 1); // number |
instanceof
能正确判断引用类型,不能精准判断原始数据类型
原理:通过递归查找原型链的方式来判断是否为构造函数的实例
1 | console.log({} instanceof Object); // true |
constructor
通过判断 constructor 确定数据类型,不可靠在于,如果创建的对象更改了原型,就不准确了。
1 | console.log((1).constructor === Number); // true |
Object.prototype.toString.call()
前几种方式或多或少都存在一些缺陷,Object.prototype.toString.call() 综合来看是最佳选择,能判断的类型最完整也最准确。
1 | const oproto = Object.prototype; |
例如判断一个对象是否为函数只需要使用if (serialize.call(fn) === '[object Function])'
即可
其他
其余的还有es6引入的新的Array方法Array.isArray
可以直接判断数组类型
综上
typeof
可以判断基础数据类型,但是遇到null
会误判为object
,不能用于判断引用数据类型instanceof
可以用于检测引用数据类型,原理是根据原型链查找是否为构造函数的实例,不能用于判断基础数据类型constructor
直接根据构造函数进行判断类型,但是如果手动更改过对象的prototype
,则不准确Object.prototype.toString.call()
方法最好最通用