一 背景 var a = 20; var b = 'abc'; var c = true; var d = { m: 20 } 因為JavaScript具有自動垃圾回收機制,所以對於前端開發來說,記憶體空間並不是一個經常被提及的概念,很容易被大家忽視。特別是很多不是電腦專業的朋友在進入到前端之後,會 ...
一 背景
var a = 20;
var b = 'abc';
var c = true;
var d = { m: 20 }
因為JavaScript具有自動垃圾回收機制,所以對於前端開發來說,記憶體空間並不是一個經常被提及的概念,很容易被大家忽視。特別是很多不是電腦專業的朋友在進入到前端之後,會對記憶體空間的認知比較模糊,甚至有些人乾脆就是一無所知.
當然也包括我自己。在很長一段時間里認為記憶體空間的概念在JS的學習中並不是那麼重要。可是後我當我回過頭來重新整理JS基礎時,發現由於對它們的模糊認知,導致了很多東西我都理解得並不明白。比如最基本的引用數據類型和引用傳遞到底是怎麼回事兒?比如淺複製與深複製有什麼不同?還有閉包,原型等等.
因此後來我才漸漸明白,想要對JS的理解更加深刻,就必須對記憶體空間有一個清晰的認知.
二 棧與堆
與c++類似,javaScipt中的記憶體也分為棧區和堆區,它們存儲數據的機制不同,導致存儲數據的類型也不同,棧區主要存儲簡單數據類型,堆區主要存儲引用數據類型.
首先我們簡單瞭解下棧的存取方式,這裡我們可以通過類比乒乓球盒子來分析。如下圖
這種乒乓球的存放方式與棧中存取數據的方式如出一轍。處於盒子中最頂層的乒乓球5,它一定是最後被放進去,但可以最先被使用。而我們想要使用底層的乒乓球1,就必須將上面的4個乒乓球取出來,讓乒乓球1處於盒子頂層。這就是棧空間先進後出,後進先出的特點。圖中已經詳細的表明瞭棧空間的存儲原理。
堆存取數據的方式,則與書架與書非常相似。書雖然也整齊的存放在書架上,但是我們只要知道書的名字,我們就可以很方便的取出我們想要的書,而不用像從乒乓球盒子里取乒乓一樣,非得將上面的所有乒乓球拿出來才能取到中間的某一個乒乓球。好比在JSON格式的數據中,我們存儲的key-value是可以無序的,因為順序的不同並不影響我們的使用,我們只需要關心書的名字。
三 複雜數據類型與基本數據類型
基礎數據類型都是一些簡單的數據段,JavaScript中有5中基礎數據類型,分別是Undefined、Null、Boolean、Number、String。基礎數據類型都是按值訪問,因為我們可以直接操作保存在變數中的實際的值。複雜數據類型 包括數組,對象等.
四 引用數據類型與堆記憶體
與其他語言不同,JS的引用數據類型,比如數組Array,它們值的大小是不固定的。引用數據類型的值是保存在堆記憶體中的對象。JavaScript不允許直接訪問堆記憶體中的位置,因此我們不能直接操作對象的堆記憶體空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。因此,引用類型的值都是按引用訪問的。這裡的引用,我們可以粗淺地理解為保存在變數對象中的一個地址,該地址與堆記憶體的實際值相關聯。
為了更好的搞懂變數對象與堆記憶體,我們可以結合以下例子與圖解進行理解.
var b = { m: 20 }; // 變數b存在棧中,對應的值就是一個索引指向對象{m: 20},{m:20}作為對象存在於堆記憶體中.
因此當我們要訪問堆記憶體中的引用數據類型時,實際上我們首先是從變數對象中獲取了該對象的地址引用(或者地址指針),然後再從堆記憶體中取得我們需要的數據。
理解了JS的記憶體空間,我們就可以藉助記憶體空間的特性來驗證一下引用類型的一些特點了。
在前端面試中我們常常會遇到這樣一個類似的題目
// demo01.js
var a = 20;
var b = a;
b = 30;
// 這時a的值是多少?
// demo02.js
var m = { a: 10, b: 20 }
var n = m;
n.a = 15;
// 這時m.a的值是多少
在變數對象中的數據發生複製行為時,系統會自動為新的變數分配一個新值。var b = a執行之後,a與b雖然值都等於20,但是他們其實已經是相互獨立互不影響的值了。具體如圖。所以我們修改了b的值以後,a的值並不會發生變化。
demo01圖解
在demo02中,我們通過var n = m執行一次複製引用類型的操作。引用類型的複製同樣也會為新的變數自動分配一個新的值保存在變數對象中,但不同的是,這個新的值,僅僅只是引用類型的一個地址指針。當地址指針相同時,儘管他們相互獨立,但是在變數對象中訪問到的具體對象實際上是同一個。如圖所示
因此當我改變n時,m也發生了變化。這就是引用類型的特性。
通過記憶體的角度來理解,是不是感覺要輕鬆很多。除此之外,我們還可以以此為基礎,一步一步的理解JavaScript的執行上下文,作用域鏈,閉包,原型鏈等重要概念。