從底層來理解Javascript變量的值與引用

入題

咱們學習Javascript,首先學習的就是變量的數據類型,ES6版Javascript內置了7種數據類型:html

  1. 布爾(Boolean)
  2. 字符串(String)
  3. 數字(Number)
  4. null
  5. undefined
  6. 對象(Object)
  7. 符號(Symbol)程序員

    最新規範中,還增長了 整數(BigInt)類型,這裏暫且不論。

這裏有幾個問題:編程

  • a的值變了嗎?爲何?
let a = 1
let b = a        
b = 2
  • a的值變了嗎?爲何?
let a = 1
let b = a

function foo(c, d) {
 c = c + d
}

foo(a, b)
  • a的值變了嗎?爲何?
let a = {
  value: 1
}
let b = a        
b.value = 2
  • a的值變了嗎?爲何?
let a = {
  value: 1
}
let b = a

function foo(c, d) {
 c = c + d
}

foo(a.value, b.value)

答案能夠本身跑一下,爲何能夠在後文中尋找。緩存

變量是怎麼存儲和修改的?

爲了更好的理解,咱們從最底層的彙編語言提及。數據結構

彙編語言

爲何須要彙編語言,你們都知道機器語言是二進制的,爲了容易讀寫,彙編語言在二進制的基礎上加上了指令名稱,好比加法指令00000011,彙編裏面就是add,這樣人類纔好閱讀和編寫機器能讀懂的指令程序。執行時轉換成對應的二進制碼便可。編程語言

再到後來,高級語言發展愈來愈快,它們的語法更接近人類的思惟方式,更受程序員歡迎。它們怎麼執行呢?運行以前,它們的編譯器會把高級語言代碼編譯成機器能讀懂的二進制編碼。函數

寄存器和內存

二進制編碼怎麼運行呢,咱們須要再瞭解兩個概念:寄存器和內存佈局

  • 寄存器,cpu只能運算,寄存器是輔助執行運算的存儲器,存儲內容諸如:參與運算的數據的內存地址、當前所需運行的指令的地址
  • 內存,內存分爲兩種:cpu緩存和內存。學習

    • cpu緩存,好比i5,i7,它們都有三級緩存,一般是幾兆,它們的訪問速度比內存條快不少,用來緩存常常使用的數據,加快訪問速度。
    • 內存,就是咱們電腦的內存條提供的存儲。大部分運行中的程序的數據,都會存儲在這裏。

簡單描述一下運算的過程:根據寄存器的地址,到內存讀取到運算指令,運算數據,而後在運算單元執行運算。編碼

內存佈局

從上面能夠了解到,程序運行數據是存放在內存中,下面咱們來看看數據在內存中是怎麼佈局的。

內存是按地址訪問的,好比,咱們有512Kb的內存,那麼內存地址就是從0x00000x8000

內存佈局會涉及兩個概念:棧和堆

  • ,從內存高位往地位分配,從0x8000開始,假如咱們要分配一個4字節的變量,那麼變量就是從0x80000x7eec。棧是用來存儲函數運行時數據,如局部變量。學過數據結構就知道,棧是後進先出的,這個就是要知足函數調用的順序,函數是一層層往下調用,而後一層層往上釋放。
  • ,從內存低位往高位分配,從0x1000開始(0x1000如下由系統使用),堆用來存儲動態變量,須要使用者本身申請和釋放(大多高級語言有垃圾回收機制,因此無需管理)。

以上這些就是彙編語言的基本存儲和運行邏輯,更多參看參考文檔1。

Javascript變量存儲和運算

鋪墊了這麼多,最後咱們回來看看Javascript的變量,究竟是怎麼存儲和修改的。

原始類型和高級類型

從存儲和訪問角度,Javascript的原生數據類型還要分爲原始類型和高級類型。

說簡單一點,原始類型就是能夠按值訪問的數據類型;高級類型就是按引用訪問的數據類型。存儲方式也不同,基本類型的變量是存放在棧區的(棧區指內存裏的棧內存);引用類型的值是同時保存在棧內存和堆內存中的對象。

這裏的棧和堆和彙編語言還有區別,假如咱們用的是v8引擎,Javascript的內存分配底層是由v8管理的。具體參看參考文檔2。

變量的訪問

編程語言中的變量名,編譯運行時關聯的就是變量的地址。

  • 原始類型,這個地址就是內存中存放變量值的地址,直接訪問就能夠取到變量值;
  • 高級類型,這個地址存放的是引用(理解爲指針也能夠),也就是這個內存地址存放的是另一個地址,用這個引用地址才能訪問到真正的變量值,這裏的變量值存放的是對象結構數據,屬性和方法可能還要繼續經過引用去訪問。

變量的修改

變量的修改也是分原始類型和高級類型。

  • 原始類型,賦值就是修改變量地址存放的數據,也就是直接被修改了。

    那麼問題來了,函數的原始類型參數會被修改嗎?字符串呢?
  • 高級類型,直接賦值修改的實際上是引用自己,並不是對象的值(引用其實你也能夠理解爲是一個數據變量)。你想修改對象的屬性,必須經過引用訪問到對象結構,而後再訪問到屬性值,再作修改。

    函數對象類型參數,能夠被修改嗎?

以上就是所有內容,最後的題目請仔細思考一下,歡迎與我討論。

參考

  1. 彙編語言入門
  2. V8 內存淺析

歡迎交流

我的讀書公衆號,歡迎交流!
讀書三到-讀書,學習技術

相關文章
相關標籤/搜索