在系列(三)中,咱們提到了「執行上下文的生命週期」,如今咱們來回顧一下:javascript
當一個函數被調用時,一個新的執行上下文就會被建立。一個執行上下文的生命週期大體能夠分爲兩個階段:建立階段和執行階段。java
建立階段:瀏覽器
在這個階段,執行上下文會分別建立變量對象,確認做用域鏈,以及肯定this的指向。bash
執行階段:微信
建立階段以後,就開始執行代碼,這個時候會完成變量賦值、函數引用、以及執行其它可執行的代碼。函數
咱們在系列(二)中也曾提到過變量對象(Variable Object),咱們在javascript代碼中聲明的全部變量都保存在變量對象中,除此以外,變量對象中還有可能包含如下內容:學習
一、函數的全部參數。this
二、當前上下文中的全部函數聲明(經過function聲明的函數)。spa
三、當前上下文中的全部變量聲明(經過var聲明的變量)。code
說了這麼屢次變量對象,那到底什麼纔是變量對象了?但願經過本次系列的學習,我能理解變量對象這個概念。
4.1 建立過程
變量對象的建立,依次經歷瞭如下幾個過程。
1. 在Chrome瀏覽器中,變量對象會首先得到函數的參數變量及其值;在FireFox瀏覽器中,是直接將參數對象argument保存在變量對象中。
2. 依次獲取當前上下文中全部聲明的函數,也就是使用function關鍵字聲明的函數。在變量對象中會以函數名創建一個屬性,屬性值爲指向該函數所在的內存地址引用。若是函數名的屬性已經存在,那麼該屬性的值會被新的引用覆蓋。
3.依次獲取當前上下文中的變量聲明,就是使用var關鍵字聲明的變量。每找到一個變量聲明,就在變量對象中就以變量名創建一個屬性,屬性值爲undefined,是undefined的哦。若是該變量名的屬性已經存在,爲了防止同名函數被修改成undefined,則會直接跳過,原屬性值不會被修改。
注意:ES6支持新的變量聲明方式let/const,規則與ar徹底不一樣,他們是在上下文的執行階段開始執行的,避免了「變量提高」帶來的一系列問題,所以這裏暫時先不介紹。
知道了上面的規則後,咱們來思考一個問題,當咱們執行如下代碼時,具體的執行過程是怎麼樣的呢?
var a = 30;複製代碼
首先,上下文的建立階段會先確認變量對象,變量對象會獲取帶var關鍵字變量,他會以變量名a創建一個屬性,屬性值爲undefined。所以第一步是:
var a = undefined;複製代碼
上下文的建立階段完畢後,開始進入執行階段,在執行階段須要完成變量賦值的工做,所以第二步是:
a = 30;複製代碼
須要注意的是,這兩步分別是執行上下文的建立階段和執行階段完成的。所以var a = undefined 這一步實際上是提早到了比較早的地方去執行了(咱們把這一過程叫作變量提高(Hoisting))。下面經過一個簡單的例子來證實。
結合以前的理解,這個例子實際的執行順序應該是:
//這個執行上下文 變量對象的建立階段
var a = undefined;
//執行階段
a = 30;複製代碼
咱們在4.1的建立過程的規則中,能夠看出,在變量對象的建立過程當中,函數聲明的執行優先級會高於變量聲明,並且同名函數會覆蓋函數與變量,可是同名的變量並不會覆蓋函數。
可是在上下的執行階段,同名的函數會被變量從新賦值。
若是您以爲上面的話,不是那麼好理解,咱們經過一個實例來感覺一下
請仔細看這段代碼.
感覺完了上面這張圖,咱們來看下代碼的執行順序:
//本執行上下文的變量對象的建立階段
function fn() { console.log('fn') };
function fn() { console.log('new fn') };
function a() { console.log('a is func') };
var a = undefined;
var fn = undefined;
//執行階段
a = 20;
console.log(a); //20;
fn(); //'new fn';
fn = 'i am not a func';
console.log(fn);
複製代碼
根據輸出結果能夠證實,在建立階段,後建立的函數fn會覆蓋前面建立的函數fn,可是變量fn並無在建立階段覆蓋函數fn(注意我說的是建立階段)。而在執行階段,a與fn的從新賦值致使他們發生了變化。
請注意這張圖,他爲何會報錯?
或許您能一眼看出來,由於fn從新賦值覆蓋後,fn就不是一個函數的引用地址了。fn()確定會報錯。
那麼問題就在這裏,爲何變量對象的建立階段。變量fn = undefined 不會覆蓋以前的已聲明的函數fn了?若是您知道,但願您能在評論區下您的答案。
記住:執行上下文的兩個階段、變量對象建立的3條規則。
這些都是我以往的學習筆記。若是您看到此筆記,但願您能指出個人錯誤。有這麼一個羣,裏面的小夥伴互相監督,堅持天天輸出本身的學習心得,不輸出就出局。但願您能加入,咱們一塊兒終身學習。歡迎添加個人我的微信號:Pan1005919589