JavaScript中有一些您作為開發(fā)人員可能不知道的主題。了解這些主題可以幫助您編寫更好的代碼。其中包括內(nèi)存生命周期、堆、棧和調(diào)用棧。在本教程中,您將了解這些主題以及JavaScript的工作原理。
JavaScript是一種非常寬容的編程語言。它允許你以多種方式做很多事情。它也為你做了很多工作。內(nèi)存管理就是其中之一。問問你自己:多少次你不得不考慮為你的變量或函數(shù)分配內(nèi)存?
當(dāng)你不再需要那些變量或函數(shù)時(shí),你需要考慮釋放這些內(nèi)存多少次?機(jī)會(huì)不止一次。這同樣適用于了解堆、堆棧和調(diào)用堆棧的工作方式,或者它到底是什么。然而,您仍然可以使用JavaScript。您仍然可以編寫每天都能工作的代碼。
這些事情你不必知道。它們也不是必需的。但是,了解它們以及它們?nèi)绾喂ぷ骺梢詭椭斫釰avaScript是如何工作的。反過來,這可以幫助您編寫更好的代碼,成為更好的JavaScript。
記憶的生命周期
讓我們從最簡單的部分開始。什么是內(nèi)存生命周期,它是關(guān)于什么的,它是如何在JavaScript中工作的?內(nèi)存生命周期是指編程語言如何使用內(nèi)存。無論哪種語言,內(nèi)存的生命周期幾乎總是相同的。它由三個(gè)步驟組成。
第一步是內(nèi)存分配。當(dāng)您分配一個(gè)變量或創(chuàng)建一個(gè)函數(shù)或?qū)ο髸r(shí),必須為它分配一定數(shù)量的內(nèi)存。第二步是內(nèi)存使用。當(dāng)您使用代碼中的數(shù)據(jù)進(jìn)行讀或?qū)懖僮鲿r(shí),您使用的是內(nèi)存。從變量中讀取或改變值就是從內(nèi)存中讀取和寫入內(nèi)存。
第三步是釋放記憶。當(dāng)你不再使用某個(gè)函數(shù)或?qū)ο髸r(shí),內(nèi)存就會(huì)被釋放。一旦釋放,就可以再次使用。這就是對(duì)內(nèi)存生命周期的概括。JavaScript的優(yōu)點(diǎn)是它為您實(shí)現(xiàn)了這三個(gè)步驟。
JavaScript根據(jù)需要分配內(nèi)存。它使您更容易處理分配的內(nèi)存。最后,它還能起重和清理所有的臟亂。它使用垃圾收集來持續(xù)檢查內(nèi)存,并在不再使用時(shí)釋放內(nèi)存。結(jié)果呢?
作為一名JavaScript開發(fā)人員,您不必?fù)?dān)心為變量或函數(shù)分配內(nèi)存。在讀取之前,您也不必?fù)?dān)心選擇正確的內(nèi)存地址。而且,你不必?fù)?dān)心釋放你過去使用過的內(nèi)存。
堆棧和內(nèi)存堆
現(xiàn)在您已經(jīng)了解了內(nèi)存生命周期的各個(gè)步驟。你知道內(nèi)存的分配,使用和釋放。你可能會(huì)問,這些變量、函數(shù)和對(duì)象實(shí)際存儲(chǔ)在哪里?答案是:視情況而定。JavaScript不會(huì)將所有這些東西存儲(chǔ)在同一個(gè)地方。
相反,JavaScript使用了兩個(gè)位置。這些位置是堆棧和內(nèi)存堆。將使用這些位置中的哪一個(gè)取決于您當(dāng)前正在使用的內(nèi)容。
堆棧
堆棧是JavaScript僅用于存儲(chǔ)靜態(tài)數(shù)據(jù)的地方。這包括基本數(shù)據(jù)類型值。例如,數(shù)字、字符串、布爾值、未定義和null。這些靜態(tài)數(shù)據(jù)還包括引用。這些引用指向您創(chuàng)建的對(duì)象和函數(shù)。
這些數(shù)據(jù)有一個(gè)共同點(diǎn)。這些數(shù)據(jù)的大小是固定的,JavaScript在編譯時(shí)就知道這個(gè)大小。這也意味著JavaScript知道它應(yīng)該分配多少內(nèi)存,并分配這個(gè)數(shù)量。這種類型的內(nèi)存分配稱為“靜態(tài)內(nèi)存分配”。它發(fā)生在代碼執(zhí)行之前。
關(guān)于靜態(tài)數(shù)據(jù)和內(nèi)存,有一點(diǎn)很重要。這些原始值的大小是有限制的。對(duì)于堆棧本身也是如此。這也有局限性。這些限制有多高取決于特定的瀏覽器和引擎。
內(nèi)存堆
JavaScript存儲(chǔ)數(shù)據(jù)的第二個(gè)地方是內(nèi)存堆。這種存儲(chǔ)更加動(dòng)態(tài)。當(dāng)涉及到內(nèi)存堆時(shí),JavaScript并不分配固定數(shù)量的內(nèi)存。相反,它在需要的時(shí)候分配內(nèi)存。這種類型的內(nèi)存分配被稱為“動(dòng)態(tài)內(nèi)存分配”。
哪些數(shù)據(jù)存儲(chǔ)在內(nèi)存堆中?堆棧是JavaScript存儲(chǔ)靜態(tài)數(shù)據(jù)的地方,而內(nèi)存堆是JavaScript存儲(chǔ)對(duì)象和函數(shù)的地方。記住,使用原語創(chuàng)建時(shí),使用的是靜態(tài)數(shù)據(jù)。JavaScript將這些靜態(tài)數(shù)據(jù)存儲(chǔ)在堆棧中。
這些數(shù)據(jù)總是固定分配內(nèi)存。另一方面,當(dāng)您創(chuàng)建對(duì)象或函數(shù)時(shí),JavaScript將它們存儲(chǔ)在內(nèi)存堆中。為這些分配的內(nèi)存不是固定的。它是根據(jù)需要?jiǎng)討B(tài)分配的。
當(dāng)您創(chuàng)建一個(gè)變量并為它賦值時(shí),它將存儲(chǔ)在堆棧中。當(dāng)你做同樣的嘗試時(shí),會(huì)發(fā)生一些不同的事情,但是是針對(duì)一個(gè)對(duì)象。如果您聲明一個(gè)變量并為它分配一個(gè)對(duì)象,將會(huì)發(fā)生兩件事。首先,JavaScript將在堆棧中為該變量分配內(nèi)存。
當(dāng)涉及到對(duì)象本身時(shí),JavaScript將把它存儲(chǔ)在內(nèi)存堆中。存在于堆棧中的那個(gè)變量將只指向內(nèi)存堆中的這個(gè)對(duì)象。該變量將是對(duì)該對(duì)象的引用。您可以將引用看作是現(xiàn)有事物的快捷方式或別名。
這些參考不是那些東西本身。它們只是那些“真實(shí)”事物的鏈接。您可以使用這些鏈接來訪問它們引用(它們鏈接到)的內(nèi)容并對(duì)其進(jìn)行操作。
復(fù)制對(duì)象和原語
這也是為什么在JavaScript中創(chuàng)建對(duì)象副本并不是那么簡單的原因。試圖通過引用來創(chuàng)建存儲(chǔ)在變量中的對(duì)象的副本不會(huì)創(chuàng)建真正的副本。它不會(huì)復(fù)制對(duì)象本身。它只復(fù)制引用那個(gè)對(duì)象。這叫做淺拷貝。
當(dāng)您更改原始對(duì)象時(shí),副本也將更改。這是因?yàn)槿匀恢挥幸粋€(gè)對(duì)象。但是,對(duì)那個(gè)對(duì)象有兩個(gè)引用(別名或鏈接)。當(dāng)您使用其中一個(gè)引用來更改對(duì)象時(shí),另一個(gè)引用仍然指向相同的對(duì)象,即您剛剛更改的對(duì)象。
當(dāng)您嘗試復(fù)制原始值時(shí),這將不會(huì)發(fā)生。當(dāng)您嘗試復(fù)制原始值,并且更改了原始值時(shí),副本將保持不變。原因是:沒有參考資料。您正在創(chuàng)建真正的副本,并直接使用這些副本。
您可能已經(jīng)聽說過所謂的“調(diào)用堆棧”。這與我們之前在本教程中討論的堆棧不同。如您所知,堆棧是JavaScript用來存儲(chǔ)用原始值賦值的變量的地方。調(diào)用堆棧是不同的。
調(diào)用堆棧是JavaScript用來跟蹤函數(shù)的一種機(jī)制。當(dāng)您調(diào)用一個(gè)函數(shù)時(shí),JavaScript會(huì)將該函數(shù)添加到調(diào)用堆棧中。如果該函數(shù)調(diào)用另一個(gè)函數(shù),JavaScript也會(huì)將該函數(shù)添加到調(diào)用堆棧中,位于第一個(gè)函數(shù)之上。
這個(gè)過程將對(duì)上一個(gè)函數(shù)調(diào)用的任何其他函數(shù)重復(fù)。當(dāng)一個(gè)函數(shù)完成時(shí),JavaScript將從調(diào)用堆棧中刪除該函數(shù)。有兩件重要的事情。第一件事是堆棧中的每個(gè)新函數(shù)都將被添加到調(diào)用堆棧的頂部。
第二件事是調(diào)用堆棧從上到下執(zhí)行。添加到堆棧的最后一個(gè)函數(shù)將作為first執(zhí)行。添加到堆棧的第一個(gè)函數(shù)將最后執(zhí)行。這也被稱為后進(jìn)先出原則。讓我們用一個(gè)簡單示例的代碼來說明這一點(diǎn)。
總結(jié):JavaScript中的內(nèi)存生命周期、堆、棧和調(diào)用棧
內(nèi)存生命周期、堆、堆棧和調(diào)用堆棧是不經(jīng)常討論的主題。沒有太多的材料可以用來更多地了解它們。我希望本教程能幫助您理解內(nèi)存生命周期、堆、堆棧和調(diào)用堆棧是什么,以及它們是如何工作的。
如果你喜歡這篇文章,請(qǐng)訂閱,這樣你就不會(huì)錯(cuò)過任何未來的帖子。