理解Javascript_01_理解內存分配
在正式開始之前,我想先說兩句,理解javascript系列博文是通過帶領大家分析javascript執行時的內存分配情況,來解釋javascript原理,具體會涵蓋javascript預加載,閉包原理,面象對象,執行模型,對象模型...,文章的視角很特別,也非常深入,希望大家能接受這種形式,并提供寶貴意見。
原始值和引用值
在ECMAScript中,變量可以存放兩種類型的值,即原始值和引用值。原始值指的就是代表原始數據類型(基本數據類型)的值,即Undefined,Null,Number,String,Boolean類型所表示的值。引用值指的就是復合數據類型的值,即Object,Function,Array,以及自定義對象,等等。
棧和堆
與原始值與引用值對應存在兩種結構的內存即棧和堆。棧是一種后進先出的數據結構,在javascript中可以通過Array來模擬棧的行為
var arr = []; //創建一個棧 arr.push("apple");//壓入元素"apple" ["apple"] arr.push("orange");//壓入元素"orange" ["apple","orange"] arr.pop();//彈出"orange" ["apple"] arr.push("banana");//壓入元素"banana" ["apple","banana"]
我們來看一下,與之對應的內存圖:
原始值是存儲在棧中的簡單數據段,也就是說,他們的值直接存儲在變量訪問的位置。
堆是存放數據的基于散列算法的數據結構,在javascript中,引用值是存放在堆中的。引用值是存儲在堆中的對象,也就是說,存儲在變量處的值(即指向對象的變量,存儲在棧中)是一個指針,指向存儲在堆中的實際對象。
例:var obj = new Object(); obj存儲在棧中它指向于new Object()這個對象,而new Object()是存放在堆中的。
那為什么引用值要放在堆中,而原始值要放在棧中,不都是在內存中嗎,為什么不放在一起呢?那接下來,讓我們來探索問題的答案!
首先,我們來看一下代碼:
function Person(id,name,age){ this.id = id; this.name = name; this.age = age; } var num = 10; var bol = true; var str = "abc"; var obj = new Object(); var arr = ['a','b','c']; var person = new Person(100,"笨蛋的座右銘",25);
然后我們來看一下內存分析圖:
變量num,bol,str為基本數據類型,它們的值,直接存放在棧中,obj,person,arr為復合數據類型,他們的引用變量存儲在棧中,指向于存儲在堆中的實際對象。
由上圖可知,我們無法直接操縱堆中的數據,也就是說我們無法直接操縱對象,但我們可以通過棧中對對象的引用來操作對象,就像我們通過遙控機操作電視機一樣,區別在于這個電視機本身并沒有控制按鈕。
現在讓我們來回答為什么引用值要放在堆中,而原始值要放在棧中的問題:記住一句話:能量是守衡的,無非是時間換空間,空間換時間的問題。堆比棧大,棧比堆的運算速度快,對象是一個復雜的結構,并且可以自由擴展,如:數組可以無限擴充,對象可以自由添加屬性。將他們放在堆中是為了不影響棧的效率。而是通過引用的方式查找到堆中的實際對象再進行操作。相對于簡單數據類型而言,簡單數據類型就比較穩定,并且它只占據很小的內存。不將簡單數據類型放在堆是因為通過引用到堆中查找實際對象是要花費時間的,而這個綜合成本遠大于直接從棧中取得實際值的成本。所以簡單數據類型的值直接存放在棧中。
總結:
程序很簡單,但它是一切的根本,基礎是最重要的,因為摩天大廈也是一塊磚一塊瓦的搭建起來的。內存是程序執行的根本,搞懂了內存,就等于搞懂了一切。