理解 | 堆內存棧內存釋放、null和{}、undefined的區別

文 / 景朝霞
來源公號 / 朝霞的光影筆記
ID / zhaoxiajingjing
圖 / 本身畫
❥❥❥❥點個贊,讓我知道你來過~❥❥❥❥

【前情提要】javascript

  1. 題目 | let和var的區別(1、二)
  2. 圖解 | let和var的區別(1、二)
  3. 題目 | 帶VAR和不帶VAR的區別
  4. 圖解 | 帶VAR和不帶VAR的區別
  5. 總結 | LET和VAR區別(3、四)
  6. 圖解 | 做用域和做用域鏈
  7. 練習題 | 做用域和做用域鏈
  8. 圖解 | 理解閉包
  9. 案例 | 閉包做用:保護和保存
  10. 圖解 | 判斷條件中的變量提高、私有變量、全局變量、arguments
  11. 理解 | 堆內存棧內存釋放、null和{}、undefined的區別

【iview】java

  1. iview低版本實現表格拖拽,滾動條列寬計算問題
  2. 案例 | iview中Table:拖拽適配列、自定義固定列、合併列
  3. 讀源碼 | 跟着大佬們學編程思想
  4. 上 | iview的Table組件合併列demo
  5. 下 | iview的Table組件合併列,升級代碼

0 / 舉個例子

var a = 10;
var obj = {
    id:'zhaoxiajingjing',
    name:'公號:朝霞的光影筆記'
};
function func(a) {
    console.log(a);
}
func(1);

公號ID:zhaoxiajingjing
△圖13.1:代碼的圖解web

內存分爲:棧內存(stack),堆內存(heap);以谷歌的webkit爲例,要清楚咱們本身在打開瀏覽器時產生的堆棧內存:編程

(1)在瀏覽器中打開頁面,瀏覽器引擎會渲染相關的代碼(包括JS代碼),把代碼自上而下執行數組

(2)瀏覽器想要執行代碼,會提供一個供代碼執行的環境:Execution Context Stack(執行環境棧ECStack)棧內存瀏覽器

(3)最開始執行的是全局代碼,因此會造成一個Execution Context(Global)全局執行上下文(EC(G)),在棧內存中執行全局代碼閉包

(4)在全局的執行上下文中有一個Variable Object (Global) 全局變量對象(VO(G)是有瀏覽器底層語言寫的),能夠把須要定義的變量和對應的值存儲在這裏iview

(5)var a =10;函數

① 建立一個值10(基本數據類型直接存儲在棧內存中)oop

② 建立一個變量a(把其直接存儲在VO(G)中)

③ 讓建立的變量a和值10關聯在一塊兒(賦值操做)

(6)let obj = {id:'zhaoxiajingjing', name:'公號:朝霞的光影筆記'};

① 建立值:

1)開闢一個 堆內存(heap),每個堆內存都有一個16進制的地址

2)把對象中的鍵值對分別存儲在堆內存中

3)把堆內存的地址存放在棧內存中,供變量的引用

②建立一個變量

③讓變量和以前建立的堆內存地址進行關聯

(7)function func(a){....}

①建立值:

1)開闢一個 堆內存(heap),每個堆內存都有一個16進制的地址

2)把函數體中的代碼以字符串的格式存入到堆內存中

3)把堆內存地址存放在棧內存中,供變量的引用

②建立一個變量(函數名也是變量名)

③讓變量和以前建立的堆內存地址進行關聯

(8)func(1);函數執行

①建立一個全新執行上下文,瀏覽器開闢一塊棧內存EC(func),而且壓入執行環境棧中,才能執行

②初始化THIS

③初始化做用域鏈

④在當前執行上下文中有一個Activation Object 活動對象(AO(函數)是有瀏覽器底層語言寫的),能夠把:形參賦值、定義的變量和值存儲在這裏

⑤代碼執行

函數執行就會造成棧內存(從內存中分配一塊空間),若是內存都不銷燬釋放,很容易致使內存溢出(爆滿,卡死了)。

數據類型:基本數據類型值和引用類型值

基本類型值:結構相對簡單,直接把建立的值存儲到棧內存便可

string、boolean、number、undefined、null、symbol

引用數據類型值:結構相對複雜(一個綜合體,包含不少值),不能直接存儲在棧內存中,須要單獨開闢空間來存儲,這個空間就是堆內存

(1)對象數據類型 object

普通對象{}、數組對象[]、正則對象/^$/、日期對象 new Date、數學函數對象 Math

(2)函數數據類型 function

1 / 棧內存釋放

棧內存的兩個做用:

一、提供代碼執行的環境

二、存儲基本類型值

打開瀏覽器造成的全局做用域是棧內存

函數執行造成的私有做用域是棧內存

基於ES6的let/const造成的塊級做用域是棧內存

....

那麼,棧內存釋放:

一、全局棧內存:關閉瀏覽器

二、私有棧內存:

(1)通常狀況下,函數執行完成,造成的私有棧內存就會被銷燬掉(除無限遞歸、無限循環等)

(2)一旦棧內存中的某個東西(通常都是堆內存的地址)被私有做用域之外的事物佔用了,則當前棧內存不能被當即釋放銷燬的(即:私有做用域中的私有變量等信息被保留下來了

2 / 堆內存釋放

堆內存的做用只有一個:存儲引用數據類型的值

建立一個引用數據類型的值,就會產生一個堆內存。

若是當前建立的堆內存不被其它東西佔用了,瀏覽器會在空閒的時候,查找每個內存的引用情況,不被佔用的都會被回收釋放掉。

let obj = {
    id:'zhaoxiajingjing'
};
let oop = obj;

此時,obj和oop都佔用着對象的堆內存,想要釋放堆內存,須要手動解除變量和值的關聯。

null:空對象指針、空對象指針、空對象指針

obj = null;
oop = null;

3 / null、{}、undefined、''空字符串的區別

null和{}的區別

null:空對象指針{}空對象不同、不同、不同

let obj = {}; // 開闢一塊堆內存,裏面內容是空的,有16進制的地址AAAFFF000
obj = null; // 把變量obj指向空對象指針,把AAAFFF000這個堆內存釋放掉
typeof null === 'object' // true
typeof {} === 'object' // true

這是瀏覽器的bug,全部存在計算機中的值都是二進制編碼存儲的,瀏覽器中的typeof方法把前三位是000的都判斷作對象。null的二進制前三位就是000,因此識別爲對象。但它不是對象。

null的數據類型是:基本類型值;null是空對象指針、空對象指針、空對象指針。

null、undefined和''空字符串的區別
let a;
console.log(a); // 輸出undefined
let b = '';
console.log(b); // 輸出 '' 空字符串
let obj = {};
console.log(obj.c); // 輸出undefined
console.log(obj); // 輸出 {}
obj = null;
console.log(obj); // 輸出 null

(1)建立了一個變量a,並未賦值,默認值是undefined

(3)建立了一個空字符串的值;建立了一個變量b;讓其與空字符串關聯。空字符串也是一個普通值。

(5)開闢一個堆內存(假設:16進制地址是AAAFFF000)裏面的目前是空的,沒有鍵值對;把堆內存地址存入棧內存中;建立了一個變量obj;讓其與棧內存的堆內存地址關聯。

(6)obj.c獲取對象obj中的屬性c,在obj中沒有該屬性,那麼獲取到的值是undefined

(8)釋放對象obj的堆內存

4 / 預告

找THIS:

(1)

var a = 10;
function func(){
    // 這裏的THIS是誰?
    console.log(this);
}
let obj = {
    id:'zhaoxiajingjing',
    name:'公號:朝霞的光影筆記',
    func:func
};

(2)

var a = 10;
function func(){
    // 這裏的THIS是誰?
    console.log(this);
}
let obj = {
    id:'zhaoxiajingjing',
    name:'公號:朝霞的光影筆記',
    func:func
};
func();
window.func();
obj.func();

公號ID:zhaoxiajingjing

相關文章
相關標籤/搜索