阿里雲最近在作活動,低至2折,有興趣能夠看看:
https://promotion.aliyun.com/...
爲了保證的可讀性,本文采用意譯而非直譯。html
這是專門探索 JavaScript 及其所構建的組件的系列文章的第 21 篇。前端
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!git
若是你錯過了前面的章節,能夠在這裏找到它們:程序員
// 聲明一些變量並初始化它們 var a = 5 let b = 'xy' const c = true // 分配新值 a = 6 b = b + 'z' c = false // 類型錯誤:不可對常量賦值
做爲程序員,聲明變量、初始化變量(或不初始化變量)以及稍後爲它們分配新值是咱們天天都要作的事情。github
可是當這樣作的時候會發生什麼呢? JavaScript 如何在內部處理這些基本功能? 更重要的是,做爲程序員,理解 JavaScript 的底層細節對咱們有什麼好處。web
下面,我打算介紹如下內容:編程
let
vs const
讓咱們從一個簡單的例子開始。下面,咱們聲明一個名爲myNumber
的變量,並用值23
初始化它。segmentfault
let myNumber = 23
當執行此代碼時,JS將執行:數組
myNumber
)建立惟一標識符(identifier)。23
存儲在分配的地址。
雖然咱們通俗地說,「myNumber 等於 23」
,更專業地說,myNumber
等於保存值 23 的內存地址,這是一個值得理解的重要區別。安全
若是咱們要建立一個名爲 newVar
的新變量並把 myNumber
賦值給它。
let newVar = myNumber
由於 myNumber
在技術上實際是等於 「0012CCGWH80
」,因此 newVar
也等於 「0012CCGWH80
」,這是保存值爲23
的內存地址。通俗地說就是 newVar
如今的值爲 23
。
由於 myNumber
等於內存地址 0012CCGWH80
,因此將它賦值給 newVar
就等於將0012CCGWH80
賦值給 newVar
。
如今,若是我這樣作會發生什麼:
myNumber = myNumber + 1
myNumber
的值確定是 24。可是newVar
的值是否也爲 24 呢?,由於它們指向相同的內存地址?
答案是否認的。因爲JS中的原始數據類型是不可變的,當 myNumber + 1
解析爲24
時,JS 將在內存中分配一個新地址,將24
做爲其值存儲,myNumber
將指向新地址。
這是另外一個例子:
let myString = 'abc' myString = myString + 'd'
雖然一個初級 JS 程序員可能會說,字母d
只是簡單在原來存放adbc
內存地址上的值,從技術上講,這是錯的。當 abc
與 d
拼接時,由於字符串也是JS中的基本數據類型,不可變的,因此須要分配一個新的內存地址,abcd
存儲在這個新的內存地址中,myString
指向這個新的內存地址。
下一步是瞭解原始數據類型的內存分配位置。
JS 內存模型能夠理解爲有兩個不一樣的區域:調用堆棧(call stack)和堆(heap)。
調用堆棧是存放原始數據類型的地方(除了函數調用以外)。上一節中聲明變量後調用堆棧的粗略表示以下。
在上圖中,我抽象出了內存地址以顯示每一個變量的值。 可是,不要忘記實際上變量指向內存地址,而後保存一個值。 這將是理解 let vs. const
一節的關鍵。
堆是存儲引用類型的地方。跟調用堆棧主要的區別在於,堆能夠存儲無序的數據,這些數據能夠動態地增加,很是適合數組和對象。
讓咱們從一個簡單的例子開始。下面,咱們聲明一個名爲myArray
的變量,並用一個空數組初始化它。
let myArray = []
當你聲明變量「myArray
」併爲其指定非原始數據類型(如「[]」)時,如下是在內存中發生的狀況:
myArray
」)
從這裏,咱們能夠 push
, pop
,或對數組作任何咱們想作的。
myArray.push("first") myArray.push("second") myArray.push("third") myArray.push("fourth") myArray.pop()
vs
const通常來講,咱們應該儘量多地使用const
,只有當咱們知道某個變量將發生改變時才使用let
。
讓咱們明確一下咱們所說的「改變」是什麼意思。
let sum = 0 sum = 1 + 2 + 3 + 4 + 5 let numbers = [] numbers.push(1) numbers.push(2) numbers.push(3) numbers.push(4) numbers.push(5)
這個程序員使用let
正確地聲明瞭sum
,由於他們知道值會改變。可是,這個程序員使用let
錯誤地聲明瞭數組 numbers
,由於他將把東西推入數組理解爲改變數組的值。
解釋「改變」的正確方法是更改內存地址
。let
容許你更改內存地址。const
不容許你更改內存地址。
const importantID = 489 importantID = 100 // 類型錯誤:賦值給常量變量
讓咱們想象一下這裏發生了什麼。
當聲明importantID
時,分配了一個內存地址,並存儲489
的值。記住,將變量importantID
看做等於內存地址。
當將100
分配給importantID
時,由於100
是一個原始數據類型,因此會分配一個新的內存地址,並將100
的值存儲這裏。
而後 JS 嘗試將新的內存地址分配給 importantID
,這就是拋出錯誤的地方,這也是咱們想要的行爲,由於咱們不想改變這個 importantID
的值。
當你將100
分配給importantID
時,其實是在嘗試分配存儲100
的新內存地址,這是不容許的,由於importantID
是用const
聲明的。
如上所述,假設的初級JS程序員使用let
錯誤地聲明瞭他們的數組。相反,他們應該用const
聲明它。這在一開始看起來可能使人困惑,我認可這一點也不直觀。
初學者會認爲數組只有在咱們能夠改變的狀況下才有用,const
使數組不可變,那麼爲何要使用它呢? 請記住:「改變」是指改變內存地址。讓咱們深刻探討一下爲何使用const聲明數組是徹底能夠的。
const myArray = []
在聲明 myArray
時,將在調用堆棧上分配內存地址,該值是在堆上分配的內存地址。堆上存儲的值是實際的空數組。想象一下,它是這樣的:
若是咱們這麼作:
myArray.push(1) myArray.push(2) myArray.push(3) myArray.push(4) myArray.push(5)
執行 push
操做實際是將數字放入堆中存在的數組。而 myArray
的內存地址沒有改變。這就是爲何雖然使用const
聲明瞭myArray,但沒有拋出任何錯誤。
myArray
仍然等於 0458AFCZX91
,它的值是另外一個內存地址22VVCX011
,它在堆上有一個數組的值。
若是咱們這樣作,就會拋出一個錯誤:
myArray = 3
因爲 3
是一個原始數據類型,所以生成一個新的調用堆棧上的內存地址,其值爲 3
,而後咱們將嘗試將新的內存地址分配給 myArray
,因爲myArray是用const聲明的,因此這是不容許的。
另外一個會拋出錯誤的例子:
myArray = ['a']
因爲[a]
是一個新的引用類型的數組,所以將分配調用堆棧上的一個新內存地址,並存儲堆上的一個內存地址的值,其它值爲 [a]
。而後,咱們嘗試將調用堆棧內存地址分配給 myArray
,這會拋出一個錯誤。
對於使用const
聲明的對象(如數組),因爲對象是引用類型,所以能夠添加鍵,更新值等等。
const myObj = {} myObj['newKey'] = 'someValue' // 這不會拋出錯誤
JavaScript 是世界上排名第一的編程語言(根據GitHub和Stack Overflow的年度開發人員調查)。 掌握併成爲「JS忍者」是咱們全部人都渴望成爲的人。
任何質量好的的 JS 課程或書籍都提倡使用let, const
來代替 var
,但他們並不必定說出緣由。 對於初學者來講,爲何某些 const 變量在「改變」其值時會拋出錯誤而其餘 const變量卻沒有。 對我來講這是有道理的,爲何這些程序員默認使用let處處避免麻煩。
可是,不建議這樣作。谷歌擁有世界上最好的一些程序員,在他們的JavaScript風格指南中說,使用 const 或 let 聲明全部本地變量。默認狀況下使用 const,除非須要從新分配變量,不使用 var 關鍵字(原文)。
雖然他們沒有明確說明緣由,但據我所知,有幾個緣由
const
聲明的變量必須在聲明時初始化,這迫使程序員常常在範圍方面更仔細地放置它們。這最終會致使更好的內存管理和性能。但願上面的解釋能幫助你開始明白爲何或者何時應該在代碼中使用 let 和 const 。
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
你的點贊是我持續分享好東西的動力,歡迎點贊!
乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。
https://github.com/qq44924588...
我是小智,公衆號「大遷世界」做者,對前端技術保持學習愛好者。我會常常分享本身所學所看的乾貨,在進階的路上,共勉!
關注公衆號,後臺回覆福利,便可看到福利,你懂的。