乐趣区

关于前端:字符串存在栈内存中那我林三心可要杠你了哦

前言

大家好,我是林三心,用最通俗易懂的话讲最难的知识点 是我的座右铭,根底是进阶的前提 是我的初心。

在咱们的认知里:根底类型存栈内存,援用数据类型存堆内存。

const a = '林三心'
const b = {
    age: 18,
    height: 180
}

超长字符串

大家都晓得, 字符串 属于 根底类型 ,所以大家会感觉 字符串 是存在 栈内存 中的,然而大家要晓得,V8 默认栈内存是 984Kib ,那如果一个 超长字符串 > 984Kib 能装的进 栈内存 吗?这也就是一个比拟经典的问题——大象装箱问题,试问:一头大象能装进一个小箱子里吗?

一探到底

堆快照

先来看一段代码

const func = function() {
  this.str1 = '林三心'
  this.str2 = 'Sunshine_Lin'
}

const a = new func()
const b = new func()

而后咱们来看看 堆快照 的详情

下面的后果能够看出:

  • a 和 b 的 str1 都指向同一个地址
  • a 和 b 的 str2 都指向同一个地址

那咱们可不可以猜测出一个论断:字符串的内容存于堆内存中,指针存于栈内存中,且雷同的字符串指向同一个堆内存地址

批改和新增字符串

咱们略微批改下代码

const func = function() {
  this.str1 = '林三心'
  this.str2 = 'Sunshine_Lin'
}

const a = new func()
const b = new func()

// 批改 str1
a.str1 = '哈哈哈哈哈哈哈哈哈哈'
// 新增 str3,跟 str2 一样
a.str3 = 'Sunshine_Lin'

再来看看现阶段的 堆快照 的详情

下面的后果能够看出:

  • str1 批改成一个新的字符串后,从新开拓了一个内存空间(新地址)
  • str3 新增之后,指针指向已有的 Sunshine_Lin 的内存空间

那咱们可不可以猜测出一个论断:新增或者批改字符串后,如果是一个之前不存在的字符串,则新开拓内存空间,如果是已有的,则间接应用已有的内存空间

源码剖析

当咱们申明一个字符串时:

  • 1、v8 外部有一个名为 stringTable hashmap 缓存了所有字符串,在 V8 浏览咱们的代码,转换形象语法树时,每遇到一个字符串,会依据其特色换算为一个 hash 值 ,插入到 hashmap 中。在之后如果遇到了 hash 值 统一的字符串,会优先从外面取出来进行比对,统一的话就不会生成新字符串类。
  • 2、缓存字符串时,依据字符串不同采取不同 hash 形式。

源码

通俗易懂总结

当咱们新建一个字符串时,V8 会从内存中查找一下是否曾经有存在的一样的字符串,找到的话间接复用。如果找不到的话,则开拓一块新的内存空间来存这个字符串,并把地址赋给变量。

大家有没有想过,为什么字符串不能通过下标索引来进行批改呢?因为字符串的批改实质上只能是通过整个的批改,而不能部分批改。

结语

我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜爱前端,想学习前端,那咱们能够交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】

退出移动版