推薦(免費):(視訊)
作用域
JavaScript 的變數被作用域所限制,如果超出了作用域,那麼變數就沒有辦法再被使用,這樣做的優點是:
而變數作用域也會按照宣告方式的不同,產生不同的作用域:
var
宣告:作用域在 函數 中let
、const
宣告:作用域在 {}
中var 宣告的變數
在函數內宣告的變數其作用域會被限制在該函數的呼叫棧中,在外部無法直接得到該作用域內的變數。下面的例子中, fn
函數內的變數在全域性下是沒有辦法檢視的。
function fn() { var a = 1; } fn(); console.log(a); // 無法得到 fn 函數內的 a 變數
所以常用 "立即函數" 來限制變數的作用域,主要是避免全域性變數的產生。
(function() { var b = 1; })(); console.log(b); // 無法得到 fn 函數內的 b 變數
let、const 宣告的變數
ES6 之後所新增的let
、const
作用域則與過去不同,改用 {}
作為作限制用域的方式,這讓 for 迴圈及部分語法避免產生多餘的變數來影響作用域。
與 var
不同的是 const
所定義的變數作用域被限制在 {}
中。所以這個例子中的變數 c
可在外部得到值,d
則無法取到。
{ var c = 1; const d = 1; } console.log(c); // 1 console.log(d); // Uncaught ReferenceError: d is not defined,無法取到變數 d
記憶體管理機制
每當我們新增一個變數時,在記憶體中就會佔用一個位置來儲存它的值,以便在程式後續執行時可以多次使用。
下面的程式碼會在記憶體中開闢一個 a
的空間來儲存數位 1 的值。
var a = 1
流程如下:
a
,不過這時還沒有賦值(原因可參考:Hoisting)a
賦值。所有的變數都會佔用記憶體空間,除此之外物件、陣列的屬性以及函數引數等也會用相同的概念進行佔用。呼叫一個函數時,每一個函數的作用域也都會反覆的進行記憶體佔用。隨著應用程式越來越複雜的情況下,如果持續的佔用記憶體而沒有進行適當的釋放,那麼記憶體可能會被耗盡。
JavaScript 引擎具有記憶體回收的機制,會釋放不再使用的變數記憶體,其基本概念為:當沒有任何的參照指向它時就會釋放記憶體。
來自MDN:collectible if there are zero references pointing to it.
記憶體釋放的驗證
下面用一個例子來說明及驗證記憶體釋放的機制,首先用一段函數來產生一個非常長的字串,長字串會佔用大量的記憶體空間。
在呼叫 randomString
函數後會返回一個很長的字串:
function randomString(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters.length; for (var i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; }
定義一個全域性變數 demoData
,這個變數會持續維持可被參照的狀態。
var demoData = []; // 全域性變數 function getData() { for (let i = 0; i < 1000; i++) { demoData.push(randomString(5000)) } } getData() console.log(demoData); // 可參照 demoData 值
執行這段程式碼後,進入 Chrome DevTools 中的 Memory 頁,這個功能可以得到當前頁面所佔用的記憶體狀況。接下來點選 "Take snapshot" 按鈕。
可以看到目前執行完這段程式碼後佔用了 6.2MB 的記憶體空間(注意:任何瀏覽器環境和外掛都會影響所佔用的記憶體狀態)。
限制變數的作用域,使變數無法再被外部參照。
此段程式碼依然會執行這個函數,也會將值賦值給變數,但外部無法再次參照 demoData
的值。
function getData() { var demoData = []; // 區域性變數 for (var i = 0; i < 1000; i++) { demoData.push(randomString(5000)) } } getData();
然後回到 Memory 頁點選 "Take snapshot" 重新取得記憶體的狀態,接下來會得到與前面不同的結果,這次只佔用了 1.2MB 的記憶體(其中 5MB 被釋放掉了)
總結
通過前面的例子,我們知道了作用域以及記憶體之間的關係,而記憶體管理也是前端打工人必須要掌握的知識(除了控制記憶體的使用大小,還需在必要時保留而不被釋放)。
以上就是講解 JS 記憶體管理機制及驗證的詳細內容,更多請關注TW511.COM其它相關文章!