JS 是 一种 弱类型的动态语言,何为动态语言:运行过程中需要检查数据类型的语⾔称为动态语言;相对应的 使用之前就需要确认其变量数据类型的称为静态语言,比如 C、JAVA。
1. 弱类型意味着你不需要告诉 JS 引擎这个或那个变量是什么数据类型,JS 引擎在运⾏代 码的时候自己会计算出来。
2. 动态意味着你可以使⽤同⼀个变量保存不同类型的数据。
JavaScript 的数据类型分为:简单数据类型(值类型) 和 复杂数据类型(引用类型)
简单数据类型:字符串(string),布尔(boolean),数字(number),undefined,null,BigInt, Symbol
复杂数据类型:对象(Object)
JS数据存储机制
内存空间
JS 执行过程种,主要有三种类型内存空间,分别是 代码空间,栈空间 和 堆空间。
![](https://img.haomeiwen.com/i10825669/8b62ba1968e5abfb.jpg)
栈空间 和 堆空间
首先看一段代码,分析其调用栈
![](https://img.haomeiwen.com/i10825669/4a630799a2624f02.png)
当代码执行完 前面两行的时候,调用栈内的情况,由于 a 和 b 是 值类型的 数据, 内存开辟一个空间 存放 a 和 b 的值。
![](https://img.haomeiwen.com/i10825669/61002327ec936954.png)
当执行到第三行 ,引用类型的值,调用栈情况又是如何:
![](https://img.haomeiwen.com/i10825669/3780344aeec0b3b7.png)
引用类型的 数据 是放在 堆空间的,栈空间只是 保存了对象的 引用地址。JS 需要访问该数据的时候,通过栈中的 应用地址来访问。
总结: 1. 简单类型的数据值都是直接保存在“栈”中的,引用类型的值是存放在“堆”中;
2. 简单类型传值,复杂类型(引用类型)传址:简单类型的赋值会完整复制变量值,复杂类型的赋值是复制引用地址。
那么为什么不把所有的数据都存放到栈中呢?
JS 引擎使用栈 来维护执行上下文的状态,如果所有的数据都存放在 栈空间,导致栈空间过大,会影响 上下文的切换效率,进而影响整个程序的 执行效率。比如,当我们执行完一个函数,只需要将 函数的执行上下文弹出栈, 将 指针往 下移动到 上一个执行上下文就可以了,函数的执行上下文 会被回收。
所以 通常情况下,栈空间都不会 太大,只要存放一些 简单类型的小数据,而 将 复杂类型的数据 放到 空间很大的 堆 空间。
接下来
![](https://img.haomeiwen.com/i10825669/ebb2e672267e8e37.png)
d 的 赋值过程,指向了堆中的同一个地址,修改 c 的 值,d 也会改变。
再谈闭包
![](https://img.haomeiwen.com/i10825669/b97834a2053c77d7.png)
![](https://img.haomeiwen.com/i10825669/c86d80448842c520.png)
1 当 JS 运行到 foo 函数,创建执行上下文;
2 编译中有 bar 函数 ,JS 引擎对 bar 做一次快速的词法扫描,发现该函数调用了 foo中的变量 a, 由于是 内部函数 引用了外部函数的变量,所以 JS 引擎判断这是 一个闭包,在堆 空间创造了一个 Closure(foo) 对象保存 a 变量。
当执行 foo 函数,闭包就产生了,foo 函数执行完毕, 返回的 bar 函数用到了 closure(foo)对象,所以 即使 foo 函数执行结束,closure(foo)依然被用到。在调用bar 函数的时候,创建的执行上下文 就包含了 closure(foo)。
总结:产生闭包的核心有两步:第一步是需要预扫描内部函数;第二步是把内部函数引用的外部变量保 存到堆中。
总结
JS 8中数据类型分为两大类: 值类型 和 引用类型,值类型数据存放在 栈中,引用类型数据存放在 堆中;将一个 值类型的变量 a 赋值 给 b,a 和 b 相互独立,互不影响;但是 引用类型 a 赋值给 b, 那么 它们指向同一个数据, a 和 b 相互影响。
网友评论