在看JS内存机制之前我们先来看一下JS是门什么样的语言,他又有哪些变量类型。
动静态,强弱类型
静态:在使用之前就需要确认其变量数据类型。
动态:在运行过程中需要检查数据类型。
强类型:不支持隐式类型转换。
弱类型:支持隐式类型转换。
而JS呢,则是一种动态弱类型的语言。
JS的变量类型
JS的变量类型分为8种,注意⚠️:其中Symbol为ES6新增,BigInt为ES11新增
类型 |
描述 |
Number |
基于IEE754标准的双精度64位二进制格式的值,范围为2的63次方减一到负的2的63次方减一 |
String |
用于表示文本数据,⚠️JS里面字符串是不可变的 |
Boolean |
布尔值,只有true和false |
Undefined |
一个没有被赋值的变量值为undefined,变量提升的默认值也是undefined |
Null |
空的初始值,只有一个值Null |
Symbol |
符号类型,唯一且不可修改 |
BigInt |
可以用任意精度表示数字,即使超出Number的安全范围也可以正常操作 |
Object |
对象,可以看作一组属性的集合 |
注意:⚠️
- typeOf Null 为Object,原因在于在JS最初版本000开头的为对象,而Null全为0,故导致为Object。
- 前七种称为基本数据类型(原始数据类型),最后一种为复杂数据类型又称为引用数据类型(合成数据类型)。
JS的内存
js的内存空间分为栈(stack)、堆(heap)、池(一般也会归类栈中)。其中栈存放变量,堆存放复杂对象,池存放常量,所以也叫常量池。
栈
栈空间就是我们之前反复提及的调用栈,是用来存储执行上下文的。基本数据类型的变量值都被保存在执行上下文中,而执行上下文又被压入到栈中,所以你也可以认为基本数据类型都是存放在栈中的(除了闭包)
堆
复杂数据类型的变量都是存储在堆中的,而复杂数据类型的引用则是存储在栈中的。当访问复杂数据类型的时候相当于多了一道转手的流程。
对比
区别 |
栈 |
堆 |
数据结构 |
栈结构 |
堆结构 |
存储内容 |
基本数据类型和复杂数据类型的引用 |
复杂数据类型和闭包 |
空间 |
空间比较小 |
空间很大 |
经过以上我们可以得出除闭包外,基本数据类型的变量都是存储在栈中,而复杂数据类型都是存储在堆中,而复杂数据类型的引用则存储在栈中。
注意⚠️:原始类型的赋值会完整复制变量值,而引用类型的赋值是复制引用地址。
问题
为什么一定要分堆和栈两个存储空间呢?
原因在于 JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率
JS变量有哪几类?
JS里面堆存储和栈存储有什么区别?
Null和Undefined的区别?
原因:
其实最初JS也是只有null,但后来JS的设计者觉得这样不太好,原因有如下两点
- null像在Java里一样,被当成一个对象。但是,JavaScript的数据类型分成原始类型(primitive)和合成类型(complex)两大类,Brendan Eich觉得表示"无"的值最好不是对象。
- JS的最初版本没有包括错误处理机制,发生数据类型不匹配时,往往是自动转换类型或者默默地失败。Brendan Eich觉得,如果null自动转为0,很不容易发现错误。
区别:
null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
null代表没有对象,即此处不应该有值,用法:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义,使用:
一变量二函数一对象
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于undefined。
- 函数没有返回值时,默认返回undefined。
- 对象没有赋值的属性,该属性的值为undefined。
参考
阮一峰Null和undefined区别
浏览器工作原理与实战