javascript變數物件函式呼叫棧作用域閉包等細解!
說明
下面程式碼演示基於window系統chrome瀏覽器環境,版本號為63.0.3239.132,32位!相關結果可能會有一點出入,請也實際為準!
相關程式碼除錯的過程中檢視結果的步驟:
-
開啟瀏覽器控制檯,切換到sources板塊,並選擇相應的原始檔;
-
在對應的原始檔程式碼左邊的行號上打上斷點;
-
然後重新整理瀏覽器,瀏覽器會在對應打斷點的程式碼出停止執行,此時我們根據需要按f11鍵一步一步的執行程式碼,並同時檢視程式碼的呼叫棧,作用域等情況,主要檢視source板塊下最右邊子板塊的Call Stack和Scope項。
相關概念梳理
其實從我自身出發,我覺的如果需要更好地理解變數物件的話,那麼需要對以下概念有一個比較基本的理解會更方便些!
- 函式呼叫棧
為了理解函式呼叫棧,我們先寫一段程式碼:
function fn1(){
console.log(`fn1`);
fn2();
};
function fn2(){
console.log(`fn2`);
};
fn1();
我們在fn2函式呼叫的地方打上斷點,然後重新整理瀏覽器,檢視Call Stack選項,會看到下面的結果:
fn1
(anonymous)
此時再按一次f11鍵,此時Call Stack顯示結果如下:
fn2
fn1
(anonymous)
這裡說明一下,anonymous指代全域性匿名呼叫函式環境,而fn1和fn2分別指代fn1函式作用域和fn2作用域環境。
我們梳理一下瀏覽器的呼叫過程:1 js進入全域性匿名函式環境,把這個所謂的匿名函式推入呼叫棧;2 發現此時又呼叫了fn1,於是把fn1函式推入呼叫棧,此時fn1在anonymous的上面; 3 緊接著,發現呼叫了fn2,於是把fn2推入呼叫棧,於是得到了上面的結果。
如果後續我們繼續按f11鍵除錯,會發現Call Stack會依次出現先面的結果:
fn2
fn1
(anonymous)
fn1
(anonymous)
(anonymous)
也就是說最後只剩下了全域性匿名函式環境,這裡強調一下,anonymous環境將會伴隨著程式執行一直存在,除非你關閉了瀏覽器。
於是我們總結得到這樣的結果:存在這樣一個呼叫棧,預設推入一個全域性匿名函式在棧底,當此時再呼叫其它全域性函式的時候,會把該函式推入棧,並在anonymous上面,如果該函式內部繼續呼叫了其它函式,那麼同樣道理,會把其它函式推入棧,放在該函式上面,最後當函式在呼叫完成的過程中,會依次退出該呼叫棧,退出的過程中會把許可權交給上一層函式,最後又迴歸了只剩下全域性匿名函式環境。於是我們說了這麼多,其實這就是函式呼叫棧!
函式呼叫棧你可以理解為函式呼叫前後包含關係:先進後出,後進先出!它描述了程式碼執行的先後順序以及當前程式碼執行控制許可權的擁有者關係等。
- 函式作用域
我們都知道javascript是沒有塊級作用域的,只有函式作用域,怎麼理解?我們看下面的程式碼:
程式碼1
for(var k = 0;k<10;k++){
//...
};
console.log(k);//輸出10
我們發現for迴圈程式碼塊執行完了之後,依然能得到k的值。再看下面的程式碼:
程式碼2
function fn3(){
var a = `a`;
};
fn3();
console.log(a);//報錯 a is not defined
我們發現在函式裡面定義的變數a,在函式外面是拿不到的,這就是函式作用域能做到的。
函式作用域能讓我們定義一些函式內部使用的與外部環境同名的變數而不會跟外部環境衝突,我們用的較多的地方就是即時函式,如下:
var a = `outer`;
(function(){
var a = `inner`;
conosle.log(a);//輸出inner
})();
console.log(a);//輸出outer
當然了在es6及後續版本javascript中,我們可以使用let和const標誌符來定義塊級變數,這裡不作討論!
這裡再做一下擴充套件,作用域中涉及到最多的一個概念就是作用域鏈,這個是什麼意思呢!看下面的程式碼:
let a = `a`;
function fn4(){
let b = `b`;
return a+b;
};
let c = fn4();
console.log(c);//輸出`ab`
作用域鏈描述的是一種函式在執行的過程中查詢變數的方式,具體來說:函式執行,如果遇到某變數,會首先在自身作用域環境查詢改變數,如果不存在,會向上一層作用域查詢變數,也就是函式呼叫棧中當前執行函式的下一層函式環境查詢變數,依次類推,直到到全域性環境中查詢,如果在全域性中都沒有找到變數的話,那麼就會報錯!
其實原型鏈也是一種描述例項屬性查詢的過程,跟作用域鏈類似!
- 閉包
恐怕接觸過javascript的開發者,聽到最多與其有關的概念就是閉包了。而且網上有很多文章和書籍都對閉包進行了說明,其實我覺的理解閉包並不難哈!我們來看段程式碼吧:
function fn5(){
let a = 0;
return function(){
a++;
console.log(a);
};
};
let fn = fn5();
fn();
我們在fn呼叫的地方打一個斷點,隨後按一次f11鍵進入fn執行環境,看下Scope項結果,會發現Scope下有一項子項:
Closure(fn5)
|_ a
我可以明確的告訴你,此時的fn5對於fn來說就是一個閉包(你可以理解是一個環境概念,該環境維護了一些內部返回的匿名函式用到的一些外部變數)!
梳理一下,閉包指得是某個函式呼叫之後,自身執行環境已不復存在,但返回了一個函式,由於該返回函式內部用到了外部函式裡面的一些變數,並又該內部函式又賦值給了其它變數,導致雖然外部函式不存在了,但是它引用的那些外部變數卻不能回收的一個環境(閉包)。
閉包用好了,可以保證好多變更的作用域週期得以提升,減少變數命名衝突,但是過多的使用閉包,也會存在記憶體洩漏的問題,因為你的很多變數都沒有被垃圾回收器回收。
進入正題,變數物件
為了讓你對變數物件整體有個最初的概念。在詳細介紹之前,我對變數物件概念作如此表述:變數物件指函式執行過程中,函式自身用到資料從哪裡來的,函式怎麼管理這些資料的等等,其實變數物件裡面儲存了函式在執行過程中所有用到的資料以及某個時刻值等!
時間倉促,後續待更新……
原文作者:掘金
本文來源: 掘金 如需轉載請聯絡原作者
相關文章
- JavaScript物件導向~ 作用域和閉包JavaScript物件
- 變數的作用域--js閉包變數JS
- javascript基礎(函式與方法的區別,變數作用域,變數和函式的宣告提前,函式作用域)(十五)JavaScript函式變數
- Javascript-this/作用域/閉包JavaScript
- 迴圈輸出——閉包、變數作用域變數
- 函式(三)作用域之變數作用域、函式巢狀中區域性函式作用域、預設值引數作用域函式變數巢狀
- 前端基礎進階(六):在chrome開發者工具中觀察函式呼叫棧、作用域鏈與閉包前端Chrome函式
- JavaScript之作用域和閉包JavaScript
- JavaScript從作用域到閉包JavaScript
- javascript函式讀取變數作用域簡單介紹JavaScript函式變數
- JavaScript 之有趣的函式(函式宣告、呼叫、預解析、作用域)JavaScript函式
- 原型模式故事鏈(5)--JS變數作用域、作用域鏈、閉包原型模式JS變數
- JavaScript變數作用域(Variable Scope)和閉包(closure)的基礎知識JavaScript變數
- Python 函式和變數作用域Python函式變數
- javascript 基礎(作用域和閉包)JavaScript
- Javascript深入之作用域與閉包JavaScript
- 【譯】終極指南:變數提升、作用域和閉包變數
- 前端筆記之JavaScript(四)關於函式、作用域、閉包那點事前端筆記JavaScript函式
- 深入理解javascript原型和閉包(14)——從【自由變數】到【作用域鏈】JavaScript原型變數
- JavaScript碎片———函式閉包(模擬物件導向)JavaScript函式物件
- JavaScript 匿名函式 閉包JavaScript函式
- 變數物件與作用域鏈變數物件
- JS基礎難點總結(函式作用域,變數提升,物件,建構函式,this)全!!!JS函式變數物件
- 十二、變數作用域:區域性變數、全域性變數,函式版名片管理系統—新增函式文件變數函式
- js中,函式的閉包、作用域跟[[Scopes]]的關係JS函式
- JavaScript中變數和作用域JavaScript變數
- JavaScript之變數及作用域JavaScript變數
- JavaScript變數作用域之殤JavaScript變數
- JavaScript 變數的作用域鏈JavaScript變數
- 函式物件、裝飾器、閉包函式函式物件
- 《JavaScript 闖關記》之作用域和閉包JavaScript
- 函數語言程式設計3-作用域與閉包函數程式設計
- Python函式引數傳遞以及變數作用域Python函式變數
- JavaScript進階系列01,函式的宣告,函式引數,函式閉包JavaScript函式
- JavaScript 函式引數解構物件JavaScript函式物件
- JavaScript 變數、作用域及記憶體詳解JavaScript變數記憶體
- 【譯】理解Javascript函式執行—呼叫棧、事件迴圈、任務等JavaScript函式事件
- JavaScript塊級作用域宣告函式JavaScript函式