JS系列之数据类型,判断方式以及存储位置
JS的数据类型
JS的数据类型分为两大类,他分为基本数据类型
,与引用数据类型
。
- 基本数据类型有: String, Boolean, Number, null, undefined。
- 引用数据类型: Object, Array, Function, Date, RegExp等。
JS数据类型存储位置
基本数据类型以及引用数据类型的地址都存在栈上,引用数据类型都存在堆上。这些估计大部分人都能知道,但是有没有人和作者一样发出疑问,为啥基本数据结构要存在栈上,引用数据类型都存在堆上,堆和栈有啥区别?
带着疑问,我顺手打开了百度,进行了一系列的`面向百度编程,最后得到的加以总结,如下:
栈是程序在编译运行的时候,系统就已经分配好了一定的空间给程序执行
,而堆不同,堆的大小是动态的,在通过构造函数生成一个对象的时候,这个时候就需要向系统申请一块地方,在执行完毕之后根据语言的不同,C语言需要程序员自己释放内存。Java,JavaScript等语言会自动进行垃圾回收,从而进行空间的释放
。程序在申请空间和释放空间时候的性能比较底下,所以堆相比于编译运行时已经确定好的空间相比,性能会有所下降。- 栈上的存取速度非常快,仅次于寄存器,既然栈上的存取速度很快,为啥引用类型还要存在堆上?首先当你生成一个对象的时候,这个对象可能是无限大的,那么当这个对象的大小超过栈的话(第二点说明了,栈内存是编译运行的时候已经确定了),就会出现栈溢出导致程序崩溃。那基础类型不会吗?基础类型的大小都是确定的,都会有一个最大值。例如字JS中的数字,
Number 类型都是浮点类型并且存储空间为 8 数节(byte)(8*8 bit位)。其中Number 类型值的整数最多15位,小数最多17位。
- 正是因为了引用类型的大小不可测,需要将其存储在空间可以自由分配的堆上。
存储的不同
栈上存的是基本类型值
,以及引用类型的地址
,引用类型的值是存在堆上的,可以通过栈上的地址去访问。
如何进行类型判断
-
typeof
用法:
typeof 变量名
typeof(表达式)
返回值:
'undefined': 对应的是基本数据类型中的 undefined 'string': 对应的基本数据类型中的 string 'boolean':对应的是基本数据类型中的 Boolean 'number': 对应的是基本数据类型中的 Number 'Object': 对应的是 基本基本数据结构中的 null 以及引用类型中的 Object Array Date RegExp等。 'function':对应的是引用类型的 Fuction
从上面的返回值我们可以看出来,typeof的类型检测,相对来说并不是很准确。因此使用typeof的话,一定要
慎重
-
instanceof
用法:被检测对象 instanceof 构造函数
原理: 用来检测
构造函数的peototype属性
是否在这个被检测的对象的原型链上
实例:
const str = ''; str instanceof String // false const boolean = false; boolean instanceof Boolean // false const arr = []; arr instanceof Array // true ... // 定义构造函数 function C(){} function D(){} var o = new C(); o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype o instanceof D; // false,因为 D.prototype 不在 o 的原型链上 o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true C.prototype instanceof Object // true,同上 C.prototype = {}; var o2 = new C(); o2 instanceof C; // true o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上. D.prototype = new C(); // 继承 var o3 = new D(); o3 instanceof D; // true o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上
从上面的的例子中我们可以看出,相比于typeof,instanceof能够精确地检测引用类型,但是对于基本类型的检测,可以说是一塌糊涂。
-
Object.prototype.toString.call();
用法:Object.prototype.toString.call(被检测对象)
原理:(ES5以前与ES6有少许不同)
在调用Object.prototype.toString方法的时候,会获取当前的
this
对象的[[Class]]属性的值,然后将计算好的值放到"[object ]"中,组成 "[objectClass代表的东西
]"。那么
[[Class]]
代表的是什么呢?在规范中是这么定义的:
一个字符串值,表明了该对象的类型.
但是问题又来了,那我们可以直接用
Object.prototype.toString
方法就行了,为啥还要调用一下call这个方法。相信大家都知道,在JS中的,谁调用我,那么我的this
就指向他,也就是说,如果不改变this指向的话,那么永远得到的值都是[object, object]。因此需要改变一下指向。ES6
之后呢,获取的不在是[[Class]]
而是[[NativeBrand]]
不过返回的也是正确的数据,大家如果想要懂得更多,可以去www.jb51.net/article/799…var toString = Object.prototype.toString; toString.call(new Date); // [object Date] toString.call(new String); // [object String] toString.call(Math); // [object Math] //Since JavaScript 1.8.5 toString.call(undefined); // [object Undefined] toString.call(null); // [object Null]
综上所述,Object.prototype.toString.call()检测是相较于typeof instanceof 最准确的。在开发中,更加建议使用Object.prototype.toString.call()去检测
function checkType(checkInstance, type) {
return Object.prototype.toString.call(checkInstance) === `[object ${type}]`;
},