JS總結:(二)執行上下文、this、作用域與閉包


知識點:

  1、執行上下文 & 作用域鏈 & 變量提升

  2、this 的七種使用場景

  3、作用域與閉包:什么是閉包,優缺點是什么,使用場景有哪些

一、執行上下文(execution context)

 1、Javascript 中代碼的運行環境分為以下三種:

  • 全局環境 - 這個是默認的代碼運行環境,一旦代碼被載入,引擎最先進入的就是這個環境。

  • 函數環境 - 當執行一個函數時,運行函數體中的代碼。

  • Eval - 在Eval函數內運行的代碼。

  JavaScript是一個單線程語言,這意味着在瀏覽器中同時只能做一件事情。JavaScript代碼的整個執行過程,分為兩個階段,代碼編譯階段與代碼執行階段。

  編譯階段由編譯器完成,將代碼翻譯成可執行代碼,這個階段作用域規則會確定。執行階段由引擎完成,主要任務是執行可執行代碼,執行上下文在這個階段創建。

  當 JavaScript 解釋器初始執行代碼,它首先默認進入全局上下文。每次調用一個函數將會創建一個新的執行上下文。 

  JavaScript引擎會以的方式來處理它們,這個棧,我們稱其為函數調用棧(call stack)。棧底永遠都是全局上下文,而棧頂就是當前正在執行的上下文。

 2、執行上下文是用於跟蹤代碼的運行情況,其特征如下:

  (1)一段代碼塊對應一個執行上下文,被封裝成函數的代碼被視作一段代碼塊,或者“全局作用域”也被視作一段代碼塊。

  (2)當程序運行,進入到某段代碼塊時,一個新的執行上下文被創建,並被放入一個 stack 中。當程序運行到這段代碼塊結尾后,對應的執行上下文被彈出 stack。

  (3)當程序在某段代碼塊中運行到某個點需要轉到了另一個代碼塊時(調用了另一個函數),那么當前的可執行上下文的狀態會被置為掛起,然后生成一個新的可執行上下文放入 stack 的頂部。

  (4)stack 最頂部的可執行上下文被稱為 running execution context。當頂部的可執行上下文被彈出后,上一個掛起的可執行上下文繼續執行。

 3、執行上下文的建立過程

    每當調用一個函數時,一個新的執行上下文就會被創建出來。然而,在javascript引擎內部,這個上下文的創建過程具體分為兩個階段:

    (1)建立階段:(發生在 一個函數被調用時 && 其函數體內的代碼執行前)

      A  生成變量對象:創建 arguments 對象 --> 檢查function函數聲明創建屬性 --> 檢查var變量聲明創建屬性;(這就是變量提升的原因)

      B  建立作用域鏈ScopeChain(作用域鏈本質上是一個指向變量對象的指針列表,它只引用不包含實際變量對象)

      C  確定this的值(所以,this的指向,是在函數被調用的時候確定的,也就是執行上下文被創建時確定的。)

    (2)代碼執行階段:

      變量賦值,函數引用,執行其它代碼

    注:a、變量對象和活動對象:他們其實都是同一個對象,只是處於執行上下文的不同生命周期。只有處於函數調用棧棧頂的執行上下文中的變量對象,才會變成活動對象。

      b、變量提升:執行上下文 創建階段 先進行function函數聲明,再進行var變量聲明,執行上下文 執行階段 再對var 變量進行賦值。

二、this的5種使用場景

 1、全局對象中的this:指向window

 2、函數中的this

    如果調用者函數,被某一個對象所擁有,那么該函數在調用時,內部的this指向該對象。

    如果函數獨立調用,那么該函數內部的this,則指向undefined。但是在非嚴格模式中,當this指向undefined時,它會被自動指向全局對象。

 3、使用call,apply顯示指定this

    JavaScript內部提供了一種機制,讓我們可以自行手動設置this的指向。它們就是call與apply。

    fn.call(obj);// fn並非屬於對象obj的方法,但是通過call,我們將fn內部的this綁定為obj,因此就可以使用this.xxx訪問obj的xxx屬性了。

      call與applay的不同:第二個參數,都是向將要執行的函數傳遞參數。其中call以一個一個的形式傳遞,apply以數組的形式傳遞。

 4、構造函數與原型方法上的this

    通過new操作符調用構造函數,會經歷以下4個階段。

    (1)創建一個新的對象;

    (2)將構造函數的this指向這個新對象;(obj.__proto__ = Fn.prototype;)

    (3)指向構造函數的代碼,為這個對象添加屬性,方法等;

    (4)返回新對象。

    因此,當new操作符調用構造函數時,this其實指向的是這個新創建的對象,最后又將新的對象返回出來,被實例對象接收。因此,我們可以說,這個時候,構造函數的this,指向了新的實例對象。

 5、箭頭函數中的this

三、閉包

  通過閉包,我們可以在其他的執行上下文中,訪問到函數的內部變量。

  閉包被保存在了全局變量中,但是閉包的作用域鏈並不會發生任何改變。在閉包中,能訪問到的變量,仍然是作用域鏈上能夠查詢到的變量。

  常應用於 模塊化與柯里化。

  缺點是內存泄露。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM