摘要:中對內存的一些了解在進行開發的過程中了解內存機制有助于開發人員能夠清晰的認識到自己寫的代碼在執行的過程中發生過什么也能夠提高項目的代碼質量內存是怎么樣的中變量存放有著原始值與引用值之分原始值原始的數據類型以及新加入的引用值等類型的值便是引用
JS中對內存的一些了解
在JS進行開發的過程中, 了解JS內存機制有助于開發人員能夠清晰的認識到自己寫的代碼在執行的過程中發生過什么, 也能夠提高項目的代碼質量.JS內存是怎么樣的?
JS中變量存放有著原始值與引用值之分:
原始值: 原始的數據類型: undefined、null、number、string、boolean以及es6新加入的symbol.
引用值: object、array、function等類型的值便是引用值.
JS中的內存也分為棧內存和堆內存. 堆與棧 詳細了解查看這里.
eg:
const str = "我是說明內存的文檔"; // 這里 str 以及 "我的說明內存的文檔" 都存儲在棧內存當中 const obj = { a: 1 }; // 這里 obj(指向存儲在堆中的數據的指針) 是存儲在棧內存 而 { a: 1 } 則存儲在堆當中內存中的存儲對象聲明周期是怎么樣的呢?
MDN中的介紹:
當對象將被需要的時候為其分配內存.
使用已分配的內存(讀、寫操作)
當對象不再被需要的時候, 釋放存儲這個對象的內存
1 2在所有語言中都是一樣的, 3在JS當中不是那么明顯
看看內存中發生了什么?let str1 = 1; // 為str1分配棧內存 str1: 1 let str2 = str1; // 原始類型直接訪問值, 即為str2新分配棧內存: str2: 1 str2 = 2; // 棧內存: str2: 2. str2的值為2, 而str1的值仍然是1 /************************ 我是分割線: 上面為原始類型 下面為復雜類型 *******************************/ let obj1 = { a: 1 }; // 為obj1分為棧內存訪問地址的指針: obj1. 堆內存中存儲對象值: { a: 1 } let obj2 = obj1; // 為obj2分配棧內存訪問地址的指針: obj2. 引用了堆內存中的值{ a: 1 } obj2.a = 2; // 通過obj1修改堆內存的數據, 由于obj2與obj2都是指向堆內存中的同一個數據的指針(也叫引用). 所以堆內存中的值{a: 1}修改為{a: 2} 即 obj1.a 為 2; obj2.a 也為 2; (這里它們是指向了堆內存中的同一個數據的不同指針) obj2 = { a: 3 }; // 因為改的是整個對象, 這里會在堆內存中創建一個新的對象值: {a:3}, 而obj2引用的是這個新對象, 所以obj1.a 依舊為 2; 而obj2.a 則為 3了. (這里它們是指向了堆內存中的不同數據的不同的指針)
然后看看這個問題:
let a = { n: 1 }; let b = a; a.x = a = { n: 2 };
具體查看詳細解釋, 對理解基礎知識點還是很有幫助的. 例如: js的賦值運算順序永遠都是從右往左的,但是.是優先級最高的運算符.
從內存角度看函數傳值的變化關于傳值/址的解說. 用原始類型和引用類型來區分. 原始類型傳的是值, 引用類型傳的則為址.
let str = "我是初始字符串"; let fn = (arg) => { console.log(arg); // #1 我是初始字符串 arg = "我是修改后的字符串"; console.log(arg); // #2 我是修改后的字符串 console.log(str); // #3 我是初始字符串 }; fn(str);
上面例子#1可以看到傳入fn的是str的值, 在棧內存中分配了新的空間來保存函數參數和其值(函數運行后自動釋放這部分內存, _垃圾回收機制_). 所以在#2出輸出的值為我是修改后的字符串. 在調用函數fn時給參數arg傳了值(在棧內存中新分配的數據), 而str又為原始類型. 在#3處輸出與初始化定義保持一致.
let obj = { a: 1 }; let fn = (arg) => { arg = { a: 2 }; }; fn(obj); // 這個時候obj還是{a: 1} let fn1 = (arg) => { arg.a = 2; }; fn1(obj); // 這個時候obj則為{a: 2}
上面這個例子中的兩個函數都是傳址, 起初傳入的參數arg都是引用(指向堆內存中的同一個數據的指針), 在fn中重新為變量arg賦值新的對象(引用類型). 而在fn1中的arg依舊是引用(指向堆內存中數據的指針), 所以fn1中是修改成功的.
垃圾回收機制JS具有垃圾回收機制, 這給開發人員帶來了極大的方便, 至少不用太考慮內存釋放的問題(有部分還是要考慮的).
函數的變量只在函數執行過程中存在. 在函數執行過程中, 函數內部的變量將會在內存中分配一定的空間, 當函數執行完畢后, 自動將這些變量從內存中釋放, 以留出空間作其它用處.
當內存中某個變量不再被引用, JS將清理掉這部分內存的分配. eg:
let obj = { a: 1 }; // 內存中存在{a: 1}對象, 以及obj這個引用地址 obj = { a: 2 }; // 垃圾回收機制自動清理{a: 1}, 并為新的有用的{a: 2}分配空間內存優化
就全局變量而言, JS不能確定它在后面是否用到, 所有它從聲明之后就一直存在于內存中, 直至手動釋放或者關閉頁面/瀏覽器, 這就導致了某些不必要的內存消耗. 我們可以進行以下優化.
使用立即執行函數
(() => { // do something... })();
手動接觸變量的引用
let obj = { a: 1, b: 2, c: 3 }; obj = null;
在JS中, 閉包是最容易產生內存問題的, 我們可以使用回調函數代替閉包來訪問內部變量. 使用回調的好處就是(針對訪問的內部變量時原始類型的值, 因為在函數傳參的時候傳的是值), 在執行后會自動釋放其中的變量, 不會像閉包一樣一直將內部變量存在于內存中(但如果是引用類型, 那么這個被引用的對象依舊在內存中).
function fn() { var val = "你好"; return function() { return val }; }; var getVal = fn(); var v = getVal(); // 你好
上面例子中, 雖然函數fn已經執行完畢, 但是對于函數中變量val的引用還在, 所以垃圾回收機制不會將函數中的val回收.
使用回調
function fn1(cb) { var val = "你好"; return cb(val); }; function fn2(arg) { return arg; }; var v = fn1(fn2);
同時聲明, 并不是說明這樣做就一定比閉包好, 閉包也有其好處, 只是需要我們在分清在最恰當的時候使用.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108255.html
摘要:內存圖示意圖內存圖就是簡化模擬示意使用的內存中的數據區中的情況,簡單的分為棧內存堆內存,如下圖。明顯,左邊是原始代碼,中間是棧內存,右邊是堆內存。如果原始代碼中變量是對象,棧內存中就會存儲堆內存的地址隨機,堆內存中會存儲這個對象的所有內容。 內存的分配(示意) 啟動程序,就需要分配內存給運行的程序。啟動瀏覽器,就會分配一定內存供瀏覽器使用,瀏覽器在會分配相應的內存供諸如HTML+CSS...
摘要:在試圖弄清這個問題之前,先要理解棧內存堆內存和預處理。因此在子函數執行的時候,堆內存被占用了,相應的棧內存也將保留。所以,棧內存在執行完之后會被保留一段時間,這段時間等于其子函數執行的時間。 在試圖弄清這個問題之前,先要理解棧內存、堆內存和預處理。 占用內存,不會銷毀的閉包實例 例1: var num = 12; function fn() { var num = 100; ...
摘要:在內部設計時分成了兩部分和。層表示內存中的數據塊,負責提供操作數據塊的接口。也就是說通過創建內存塊,通過實現對內存塊的讀寫操作。很顯然中的結果是。有同學可能對輸出的順序不理解,覺得為什么不是呢。上例在小端模式下的存儲形式,每個框框表示位。 我們知道在C語言中,可以使用malloc和free方法來分配和釋放內存。隨著web的發展中,js在ES6中新增了內存操作的支持。其實現方式就是---...
摘要:前言為了研究對原子類的實現,從類開始,分析如果對原子操作的實現。保存著基礎數據,使用修飾,可以保證該值對內存可見,也是原子類實現的理論保障。使用自旋鎖來處理并發問題。 前言 為了研究Java對原子類的實現,從AtomicInteger類開始,分析Java如果對原子操作的實現。 什么是原子操作? 原子操作是指不會被線程調度機制打斷的操作;這種操作一旦開始,就一直運行到結束,中間不會有任何...
閱讀 1624·2021-11-22 13:53
閱讀 2856·2021-11-15 18:10
閱讀 2762·2021-09-23 11:21
閱讀 2506·2019-08-30 15:55
閱讀 482·2019-08-30 13:02
閱讀 757·2019-08-29 17:22
閱讀 1667·2019-08-29 13:56
閱讀 3458·2019-08-29 11:31