在正式開始之前,我想先說兩句,理解javascript系列博文是通過帶領大家分析javascript執行時的內存分配情況,來解釋javascript原理,具體會涵蓋javascript預加載,閉包原理,面象對象,執行模型,對象模型...,文章的視角很特別,也非常深入,希望大家能接受這種形式,並提供寶貴意見。
原始值和引用值
在ECMAScript中,變量可以存放兩種類型的值,即原始值和引用值。
原始值指的就是代表原始數據類型(基本數據類型)的值,即Undefined,Null,Number,String,Boolean類型所表示的值。
引用值指的就是複合數據類型的值,即Object,Function,Array,以及自定義對象,等等
棧和堆
與原始值與引用值對應存在兩種結構的內存即棧和堆
棧是一種後進先出的數據結構,在javascript中可以通過Array來模擬棧的行爲
1
2
3
4
5
|
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()是存放在堆中的。
那爲什麼引用值要放在堆中,而原始值要放在棧中,不都是在內存中嗎,爲什麼不放在一起呢?那接下來,讓我們來探索問題的答案!
首先,我們來看一下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
|
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爲複合數據類型,他們的引用變量存儲在棧中,指向於存儲在堆中的實際對象。
由上圖可知,我們無法直接操縱堆中的數據,也就是說我們無法直接操縱對象,但我們可以通過棧中對對象的引用來操作對象,就像我們通過遙控機操作電視機一樣,區別在於這個電視機本身並沒有控制按鈕。
現在讓我們來回答爲什麼引用值要放在堆中,而原始值要放在棧中的問題:
記住一句話:能量是守衡的,無非是時間換空間,空間換時間的問題
堆比棧大,棧比堆的運算速度快,對象是一個複雜的結構,並且可以自由擴展,如:數組可以無限擴充,對象可以自由添加屬性。將他們放在堆中是爲了不影響棧的效率。而是通過引用的方式查找到堆中的實際對象再進行操作。相對於簡單數據類型而言,簡單數據類型就比較穩定,並且它只佔據很小的內存。不將簡單數據類型放在堆是因爲通過引用到堆中查找實際對象是要花費時間的,而這個綜合成本遠大於直接從棧中取得實際值的成本。所以簡單數據類型的值直接存放在棧中。
總結:
程序很簡單,但它是一切的根本,基礎是最重要的,因爲摩天大廈也是一塊磚一塊瓦的搭建起來的。
內存是程序執行的根本,搞懂了內存,就等於搞懂了一切。
心血之作,鼓勵一下自已,加油!