Appearance
前言
相信很多小伙伴在学习基础类型和引用类型时经常看到一些文章介绍。基础类型保存在栈内存中,引用类型保存在堆内存中,然后栈内存是一个关联数组的结构,里面保存了变量名和值的映射关系。其中基础类型的直value 直接是值
| 变量名 | 值 |
|---|---|
| a | 0x111111 |
| b | 0x111112 |
引用类型保存的是指向的堆内存地址。然后具体的值在堆内存中。当变量赋值时,就是将栈内存的值复制到另一个变量。堆内存是一个无序的结构,栈内存时一个固定长度的结构,value固定是8b(这也是number 类型64位双精度的由来)
看完这些介绍,难道小伙伴没有疑问吗,
- 为什么要用栈内存,栈不是先进后出的结构吗,如何做到快读的查找。
- 如果堆内存中某个属性又是个基础类型,这个基础类型又保存在哪儿?
- 比如在全局申明一个var a = 1,应该保存在栈内存中吧,但是window.a 也等于1,又应该保存在堆内存中。这就矛盾了。
js中的栈内存和堆内存
栈内存是一个线性的、规则的、大小基本固定的、有序的排列起来的一块块内存空间,每个单元大小固定,规则有序的排列下来。栈内存由系统自动分配。Boolean、Null、Undefined、Number保存在栈类型中 同学们会有误解为什么要采用栈内存啊,其实栈内存和栈没什么关系,只是借用了c++中的指针是按照栈来保存的,查找时不会先出栈在读取,而是一种具有hash结构映射关系,所以不要纠结了。
堆内存是无序的结构,长度大小也不固定,只能通过地址索引到。
为什么string内保存很长
栈内存照理只有64位,保存字符串按理上不会太长。实际字符串值也是保存的指向另一个空间的内存地址(我还不知道是啥空间,就是称为系统)。当需要一个字符串时,字符串空间就会申请一个地址来保存字符串,同时栈内存中指向这个地址,类似于引用类型。这也是为什么我们在repeat函数中,尽量减少字符串拼接。
找到了找到了,大佬的文章
https://www.51cto.com/article/694979.html
当我们声明一个字符串时:
v8内部有一个名为stringTable的hashmap缓存了所有字符串,在V8阅读我们的代码,转换抽象语法树时,每遇到一个字符串,会根据其特征换算为一个hash值,插入到hashmap中。 在之后如果遇到了hash值一致的字符串,会优先从里面取出来进行比对,一致的话就不会生成新字符串类。
缓存字符串时,根据字符串不同采取不同hash方式。
所以让我们梳理一下,在我们创建字符串的时候,V8会先从内存中(哈希表)查找是否有已经创建的完全一致的字符串,如果存在,直接复用。如果不存在,则开辟一块新的内存空间存进这个字符串,然后把地址赋到变量中。这也是为什么我们不能直接用下标的方式修改字符串: V8中的字符串都是不可变的。
最终结论
从来就没有栈内存,永远都是堆内存。下面是V8 引擎的官方讲解
JavaScript values in V8 are represented as objects and allocated on the V8 heap, no matter if they are objects, arrays, numbers or strings. This allows us to represent any value as a pointer to an object.
后文
其实掌握这些知识没有什么作用,对于写代码没什么帮助,但是在设计到buffer编程时,可能会有些困惑。
https://mdnice.com/writing/7bc5fe7ffba2434c8eb997af03420ed3
https://www.cnblogs.com/Qooo/p/13685207.htmlhttps://www.51cto.com/article/694979.html
