淺析JS中的堆內存與棧內存
最近跟著組里的大佬面試碰到這么一個問題前普,
Q:說說var、let贰军、const的區(qū)別
A:balabalabalabla...
Q:const定義的值能改么奸远?
A:你逗我灌危?不能吧
不知道各位看官怎么想制肮?答案是部分能改冒窍,部分不能改。const定義的基本類型不能改變豺鼻,但是定義的對象是可以通過修改對象屬性等方法來改變的综液。如,
>>> const a = 1
>>> a
<<< 1
>>> a = 2
<<< VM1750:1 Uncaught TypeError: Assignment to constant variable.
at <anonymous>:1:3
(anonymous) @ VM1750:1
>>> const b = {}
>>> b
<<< {}
>>> b.name = 1
>>> b
<<< {name: 1}
>>> b = {}
<<< VM1785:1 Uncaught TypeError: Assignment to constant variable.
at <anonymous>:1:4
const不是定義常量么儒飒?為什么還能改谬莹?這就是我們今天要說的重點~
js中的堆內存與棧內存
在js引擎中對變量的存儲主要有兩種位置,堆內存和棧內存桩了。
和java中對內存的處理類似附帽,棧內存主要用于存儲各種基本類型的變量,包括Boolean井誉、Number蕉扮、String、Undefined颗圣、Null慢显,**以及對象變量的指針爪模,這時候棧內存給人的感覺就像一個線性排列的空間欠啤,每個小單元大小基本相等荚藻。
而堆內存主要負責像對象Object這種變量類型的存儲,如下圖
棧內存中的變量一般都是已知大小或者有范圍上限的洁段,算作一種簡單存儲应狱。而堆內存存儲的對象類型數(shù)據(jù)對于大小這方面,一般都是未知的祠丝。個人認為疾呻,這也是為什么null作為一個object類型的變量卻存儲在棧內存中的原因。
因此當我們定義一個const對象的時候写半,我們說的常量其實是指針岸蜗,就是const對象對應的堆內存指向是不變的,但是堆內存中的數(shù)據(jù)本身的大小或者屬性是可變的叠蝇。而對于const定義的基礎變量而言璃岳,這個值就相當于const對象的指針,是不可變悔捶。
既然知道了const在內存中的存儲铃慷,那么const、let定義的變量不能二次定義的流程也就比較容易猜出來了蜕该,每次使用const或者let去初始化一個變量的時候犁柜,會首先遍歷當前的內存棧,看看有沒有重名變量堂淡,有的話就返回錯誤馋缅。
說到這里,有一個十分很容易忽略的點绢淀,之前也是自己一直沒有注意的就是萤悴,使用new關鍵字初始化的之后是不存儲在棧內存中的。為什么呢更啄?new大家都知道稚疹,根據(jù)構造函數(shù)生成新實例,這個時候生成的是對象祭务,而不是基本類型内狗。再看一個例子
var a = new String('123')
var b = String('123')
var c = '123'
console.log(a==b, a===b, b==c, b===c, a==c, a===c)
>>> true false true true true false
console.log(typeof a)
>>> 'object'
我們可以看到new一個String,出來的是對象义锥,而直接字面量賦值和工廠模式出來的都是字符串柳沙。但是根據(jù)我們上面的分析大小相對固定可預期的即便是對象也可以存儲在棧內存的,比如null拌倍,為啥這個不是呢赂鲤?再繼續(xù)看
var a = new String('123')
var b = new String('123')
console.log(a==b, a===b)
>>> false false
很明顯噪径,如果a,b是存儲在棧內存中的話数初,兩者應該是明顯相等的找爱,就像null === null是true一樣,但結果兩者并不相等泡孩,說明兩者都是存儲在堆內存中的车摄,指針指向不一致。
說到這里仑鸥,再去想一想我們常說的值類型和引用類型其實說的就是棧內存變量和堆內存變量吮播,再想想值傳遞和引用傳遞、深拷貝和淺拷貝眼俊,都是圍繞堆棧內存展開的意狠,一個是處理值,一個是處理指針疮胖。
內存分配和垃圾回收
一般來說棧內存線性有序存儲环戈,容量小,系統(tǒng)分配效率高获列。而堆內存首先要在堆內存新分配存儲區(qū)域谷市,之后又要把指針存儲到棧內存中,效率相對就要低一些了击孩。
垃圾回收方面迫悠,棧內存變量基本上用完就回收了,而推內存中的變量因為存在很多不確定的引用巩梢,只有當所有調用的變量全部銷毀之后才能回收创泄。
繼續(xù)往下思考的話,其中還有很多的東西需要去學習括蝠,今天先到這里鞠抑,后續(xù)再來補充。
話說~NaN會不會也是存儲在堆內存中的呢忌警?大家想想吧搁拙,歡迎大家來一起討論討論~文中如有錯誤歡迎指出~