深入理解JavaScript特性
最近在讀《JavaScript高級程序設計》這一本書,裏面提到了JavaScript的特征,倍感興趣,於是結合自己的認識,在這裏進行一下總結。
1、JavaScript的垃圾回收機制
javaScript中的5種數據類型存放在棧中(Undefined、Null、Boolean、Number、String),非基本數據類型存放在堆中,占用內存,堆不會被程序自動釋放。
一張圖看懂JS中數據類型的存放位置:基本數據類型存放在棧中,非基本數據類型存放在堆中(對象),變量obi1在棧中存儲的只是堆中對象的地址。
聲明變量a=對象,只是聲明一個指針地址指向存儲該對象的內存空間,每多一個指向同一內存空間的指針地址,該對象的引用計數就會加1。
如果代碼在運行過程中有一個對象不再被需要了,但是引用計數不為零,垃圾回收機制就不能釋放這塊內存,這就被稱為內存泄漏。
釋放內存的方法就是 接觸對該內存地址的引用,將引用他的指針地址設置為null,如:a=null;
2、JavaScript 單線程(同一個時間只能做一件事)核心特征
JS除了主線程之外還存在一個任務隊列,(js單線程所有任務必須排隊完成)。
js計算能力很弱如果存在一個耗時較長的任務,後一個任務就必須等待很長時間讓前一個任務執行完畢,,如果是網絡請求他的耗時完全取決於網絡狀況,(Ajax)不符合js設計邏輯。
主線程可以忽略io(input/output)設備,掛起處於等待中的任務(監聽事件綁定的任務,ajax網絡請求)先運行排在後面的任務,,等到io設備有了返回結果,再回過頭把掛起任務執行下去 (異步事件)。
所有任務分兩種synchronous同步事件asynchronous異步事件,在js中:
同步事件在主線程上排隊執行(前一個執行完畢,後一個才能執行)。
異步事件不進入主線程,而進入任務隊列(task queue),只有任務任務隊列通知主線程,某個異步任務可以執行了,該任務才會從任務隊列中取出進入主線程。
3、JavaScript運行機制步驟
(1)所有同步任務都在主線程上依次執行,形成(執行棧)。棧的定義:先進後出,後進先出。
舉個例子:定義三個函數,sayHello函數直接在student函數體內調用,isAdult函數作為參數傳給了sayHello函數,在這裏isAdult也是一個回調函數。
三個函數進入執行棧的順序依次是:student,sayHello,isAdult
function student(){ var age = 18; var name = ‘小李‘ sayHello(name,age,isAdult(age)) console.log("student函數") //最後出棧 } function isAdult(age){ var result = age >= 18 ? ‘成年‘:‘未成年‘ console.log("isAdult函數") //最先出棧 return result; } function sayHello(name,age,reust){ console.log(‘hello!This is ‘+name+‘ ‘+age+‘years old 我‘ + reust) console.log("sayHello函數") }
student();
看輸出結果:三個函數進入執行棧的順序依次是:isAdult,student,sayHello
(2)主線程之外,存在一個任務隊列,只要異步任務有了返回結果,該任務就會被放入任務隊列中。
(3)執行棧中所有任務執行完畢後,就會訪問任務隊列,檢查隊列中有哪些事件,獲取任務隊列中最先等待的事件,讓該事件進入執行棧,開始執行。
(4)不斷重復第三步。
4、JavaScript中回調函數callback(事件綁定函數)
例:綁定點擊事件,當點擊事件觸發時 js會調用事件綁定的函數該函數稱為事件的回調函數(異步任務必須指定回調函數)。
任務隊列 先進先出數據結構,排在前面的事件會先被主線程讀取,所以如果隊列中有‘定時器‘,定時器未必準時觸發,取決於前一個任務隊列中的函數執行的結束。
5、JavaScript中內存區域
程序運行時,需要內存空間存放數據,分別為stack(棧)和heap(堆)。
棧是有結構的,每個區塊按照一定的順序取存放,可以明確的知道每個區塊的大小,而堆是沒有結構的,數據任意存放,因此棧的調用要快於堆。
每個線程分配一個棧,每個進程分配一個堆,stack是線程獨占,heap是線程公用的。
棧是系統自動開辟的自動釋放的, 堆是程序員手動開辟和釋放的。
深入理解JavaScript特性